Skip to content

Commit 7b55296

Browse files
committedFeb 20, 2023
Auto merge of #105961 - fmease:iat-type-directed-probing, r=jackh726
Type-directed probing for inherent associated types When probing for inherent associated types (IATs), equate the Self-type found in the projection with the Self-type of the relevant inherent impl blocks and check if all predicates are satisfied. Previously, we didn't look at the Self-type or at the bounds and just picked the first inherent impl block containing an associated type with the name we were searching for which is obviously incorrect. Regarding the implementation, I basically copied what we do during method probing (`assemble_inherent_impl_probe`, `consider_probe`). Unfortunately, I had to duplicate a lot of the diagnostic code found in `rustc_hir_typeck::method::suggest` which we don't have access to in `rustc_hir_analysis`. Not sure if there is a simple way to unify the error handling. Note that in the future, `rustc_hir_analysis::astconv` might not actually be the place where we resolve inherent associated types (see #103621 (comment)) but `rustc_hir_typeck` (?) in which case the duplication may naturally just disappear. While inherent associated *constants* are currently resolved during "method" probing, I did not find a straightforward way to incorporate IAT lookup into it as types and values (functions & constants) are two separate entities for which distinct code paths are taken. Fixes #104251 (incl. #104251 (comment)). Fixes #105305. Fixes #107468. `@rustbot` label T-types F-inherent_associated_types r? types
2 parents 21e5b94 + f2253da commit 7b55296

29 files changed

+946
-84
lines changed
 

‎compiler/rustc_hir_analysis/src/astconv/errors.rs

+228-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use crate::astconv::AstConv;
22
use crate::errors::{ManualImplementation, MissingTypeParams};
33
use rustc_data_structures::fx::FxHashMap;
4-
use rustc_errors::{pluralize, struct_span_err, Applicability, ErrorGuaranteed};
4+
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
55
use rustc_hir as hir;
66
use rustc_hir::def_id::DefId;
7-
use rustc_middle::ty;
7+
use rustc_infer::traits::FulfillmentError;
8+
use rustc_middle::ty::{self, Ty};
89
use rustc_session::parse::feature_err;
910
use rustc_span::lev_distance::find_best_match_for_name;
1011
use rustc_span::symbol::{sym, Ident};
@@ -221,6 +222,231 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
221222
err.emit()
222223
}
223224

225+
pub(crate) fn complain_about_ambiguous_inherent_assoc_type(
226+
&self,
227+
name: Ident,
228+
candidates: Vec<DefId>,
229+
span: Span,
230+
) -> ErrorGuaranteed {
231+
let mut err = struct_span_err!(
232+
self.tcx().sess,
233+
name.span,
234+
E0034,
235+
"multiple applicable items in scope"
236+
);
237+
err.span_label(name.span, format!("multiple `{name}` found"));
238+
self.note_ambiguous_inherent_assoc_type(&mut err, candidates, span);
239+
err.emit()
240+
}
241+
242+
// FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate.
243+
fn note_ambiguous_inherent_assoc_type(
244+
&self,
245+
err: &mut Diagnostic,
246+
candidates: Vec<DefId>,
247+
span: Span,
248+
) {
249+
let tcx = self.tcx();
250+
251+
// Dynamic limit to avoid hiding just one candidate, which is silly.
252+
let limit = if candidates.len() == 5 { 5 } else { 4 };
253+
254+
for (index, &item) in candidates.iter().take(limit).enumerate() {
255+
let impl_ = tcx.impl_of_method(item).unwrap();
256+
257+
let note_span = if item.is_local() {
258+
Some(tcx.def_span(item))
259+
} else if impl_.is_local() {
260+
Some(tcx.def_span(impl_))
261+
} else {
262+
None
263+
};
264+
265+
let title = if candidates.len() > 1 {
266+
format!("candidate #{}", index + 1)
267+
} else {
268+
"the candidate".into()
269+
};
270+
271+
let impl_ty = tcx.at(span).type_of(impl_).subst_identity();
272+
let note = format!("{title} is defined in an impl for the type `{impl_ty}`");
273+
274+
if let Some(span) = note_span {
275+
err.span_note(span, &note);
276+
} else {
277+
err.note(&note);
278+
}
279+
}
280+
if candidates.len() > limit {
281+
err.note(&format!("and {} others", candidates.len() - limit));
282+
}
283+
}
284+
285+
// FIXME(inherent_associated_types): Find similarly named associated types and suggest them.
286+
pub(crate) fn complain_about_inherent_assoc_type_not_found(
287+
&self,
288+
name: Ident,
289+
self_ty: Ty<'tcx>,
290+
candidates: Vec<(DefId, (DefId, DefId))>,
291+
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
292+
span: Span,
293+
) -> ErrorGuaranteed {
294+
// FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
295+
// Either
296+
// * update this code by applying changes similar to #106702 or by taking a
297+
// Vec<(DefId, (DefId, DefId), Option<Vec<FulfillmentError<'tcx>>>)> or
298+
// * deduplicate this code across the two crates.
299+
300+
let tcx = self.tcx();
301+
302+
let adt_did = self_ty.ty_adt_def().map(|def| def.did());
303+
let add_def_label = |err: &mut Diagnostic| {
304+
if let Some(did) = adt_did {
305+
err.span_label(
306+
tcx.def_span(did),
307+
format!(
308+
"associated item `{name}` not found for this {}",
309+
tcx.def_kind(did).descr(did)
310+
),
311+
);
312+
}
313+
};
314+
315+
if fulfillment_errors.is_empty() {
316+
// FIXME(fmease): Copied from `rustc_hir_typeck::method::probe`. Deduplicate.
317+
318+
let limit = if candidates.len() == 5 { 5 } else { 4 };
319+
let type_candidates = candidates
320+
.iter()
321+
.take(limit)
322+
.map(|&(impl_, _)| format!("- `{}`", tcx.at(span).type_of(impl_).subst_identity()))
323+
.collect::<Vec<_>>()
324+
.join("\n");
325+
let additional_types = if candidates.len() > limit {
326+
format!("\nand {} more types", candidates.len() - limit)
327+
} else {
328+
String::new()
329+
};
330+
331+
let mut err = struct_span_err!(
332+
tcx.sess,
333+
name.span,
334+
E0220,
335+
"associated type `{name}` not found for `{self_ty}` in the current scope"
336+
);
337+
err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
338+
err.note(&format!(
339+
"the associated type was found for\n{type_candidates}{additional_types}",
340+
));
341+
add_def_label(&mut err);
342+
return err.emit();
343+
}
344+
345+
let mut bound_spans = Vec::new();
346+
347+
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
348+
let msg = format!(
349+
"doesn't satisfy `{}`",
350+
if obligation.len() > 50 { quiet } else { obligation }
351+
);
352+
match &self_ty.kind() {
353+
// Point at the type that couldn't satisfy the bound.
354+
ty::Adt(def, _) => bound_spans.push((tcx.def_span(def.did()), msg)),
355+
// Point at the trait object that couldn't satisfy the bound.
356+
ty::Dynamic(preds, _, _) => {
357+
for pred in preds.iter() {
358+
match pred.skip_binder() {
359+
ty::ExistentialPredicate::Trait(tr) => {
360+
bound_spans.push((tcx.def_span(tr.def_id), msg.clone()))
361+
}
362+
ty::ExistentialPredicate::Projection(_)
363+
| ty::ExistentialPredicate::AutoTrait(_) => {}
364+
}
365+
}
366+
}
367+
// Point at the closure that couldn't satisfy the bound.
368+
ty::Closure(def_id, _) => {
369+
bound_spans.push((tcx.def_span(*def_id), format!("doesn't satisfy `{quiet}`")))
370+
}
371+
_ => {}
372+
}
373+
};
374+
375+
let format_pred = |pred: ty::Predicate<'tcx>| {
376+
let bound_predicate = pred.kind();
377+
match bound_predicate.skip_binder() {
378+
ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
379+
let pred = bound_predicate.rebind(pred);
380+
// `<Foo as Iterator>::Item = String`.
381+
let projection_ty = pred.skip_binder().projection_ty;
382+
383+
let substs_with_infer_self = tcx.mk_substs(
384+
std::iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
385+
.chain(projection_ty.substs.iter().skip(1)),
386+
);
387+
388+
let quiet_projection_ty =
389+
tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
390+
391+
let term = pred.skip_binder().term;
392+
393+
let obligation = format!("{projection_ty} = {term}");
394+
let quiet = format!("{quiet_projection_ty} = {term}");
395+
396+
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
397+
Some((obligation, projection_ty.self_ty()))
398+
}
399+
ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
400+
let p = poly_trait_ref.trait_ref;
401+
let self_ty = p.self_ty();
402+
let path = p.print_only_trait_path();
403+
let obligation = format!("{self_ty}: {path}");
404+
let quiet = format!("_: {path}");
405+
bound_span_label(self_ty, &obligation, &quiet);
406+
Some((obligation, self_ty))
407+
}
408+
_ => None,
409+
}
410+
};
411+
412+
// FIXME(fmease): `rustc_hir_typeck::method::suggest` uses a `skip_list` to filter out some bounds.
413+
// I would do the same here if it didn't mean more code duplication.
414+
let mut bounds: Vec<_> = fulfillment_errors
415+
.into_iter()
416+
.map(|error| error.root_obligation.predicate)
417+
.filter_map(format_pred)
418+
.map(|(p, _)| format!("`{}`", p))
419+
.collect();
420+
bounds.sort();
421+
bounds.dedup();
422+
423+
let mut err = tcx.sess.struct_span_err(
424+
name.span,
425+
&format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
426+
);
427+
if !bounds.is_empty() {
428+
err.note(&format!(
429+
"the following trait bounds were not satisfied:\n{}",
430+
bounds.join("\n")
431+
));
432+
}
433+
err.span_label(
434+
name.span,
435+
format!("associated type cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
436+
);
437+
438+
bound_spans.sort();
439+
bound_spans.dedup();
440+
for (span, msg) in bound_spans {
441+
if !tcx.sess.source_map().is_span_accessible(span) {
442+
continue;
443+
}
444+
err.span_label(span, &msg);
445+
}
446+
add_def_label(&mut err);
447+
err.emit()
448+
}
449+
224450
/// When there are any missing associated types, emit an E0191 error and attempt to supply a
225451
/// reasonable suggestion on how to write it. For the case of multiple associated types in the
226452
/// same trait bound have the same name (as they come from different supertraits), we instead

‎compiler/rustc_hir_analysis/src/astconv/mod.rs

+213-53
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
2727
use rustc_hir::def_id::{DefId, LocalDefId};
2828
use rustc_hir::intravisit::{walk_generics, Visitor as _};
2929
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
30+
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
3031
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
32+
use rustc_infer::traits::ObligationCause;
33+
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
3134
use rustc_middle::middle::stability::AllowUnstable;
3235
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
3336
use rustc_middle::ty::DynKind;
@@ -39,12 +42,11 @@ use rustc_span::lev_distance::find_best_match_for_name;
3942
use rustc_span::symbol::{kw, Ident, Symbol};
4043
use rustc_span::{sym, Span, DUMMY_SP};
4144
use rustc_target::spec::abi;
42-
use rustc_trait_selection::traits;
43-
use rustc_trait_selection::traits::astconv_object_safety_violations;
4445
use rustc_trait_selection::traits::error_reporting::{
4546
report_object_safety_error, suggestions::NextTypeParamName,
4647
};
4748
use rustc_trait_selection::traits::wf::object_region_bounds;
49+
use rustc_trait_selection::traits::{self, astconv_object_safety_violations, ObligationCtxt};
4850

4951
use smallvec::{smallvec, SmallVec};
5052
use std::collections::BTreeSet;
@@ -1944,7 +1946,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
19441946
Res::Err
19451947
};
19461948

1947-
// Check if we have an enum variant.
1949+
// Check if we have an enum variant or an inherent associated type.
19481950
let mut variant_resolution = None;
19491951
if let Some(adt_def) = self.probe_adt(span, qself_ty) {
19501952
if adt_def.is_enum() {
@@ -2043,23 +2045,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
20432045
}
20442046
}
20452047

2046-
// see if we can satisfy using an inherent associated type
2047-
for &impl_ in tcx.inherent_impls(adt_def.did()) {
2048-
let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else {
2049-
continue;
2050-
};
2051-
let ty::Adt(_, adt_substs) = qself_ty.kind() else {
2052-
// FIXME(inherent_associated_types)
2053-
bug!("unimplemented: non-adt self of inherent assoc ty");
2054-
};
2055-
let item_substs = self.create_substs_for_associated_item(
2056-
span,
2057-
assoc_ty_did,
2058-
assoc_segment,
2059-
adt_substs,
2060-
);
2061-
let ty = tcx.type_of(assoc_ty_did).subst(tcx, item_substs);
2062-
return Ok((ty, DefKind::AssocTy, assoc_ty_did));
2048+
if let Some((ty, did)) = self.lookup_inherent_assoc_ty(
2049+
assoc_ident,
2050+
assoc_segment,
2051+
adt_def.did(),
2052+
qself_ty,
2053+
hir_ref_id,
2054+
span,
2055+
)? {
2056+
return Ok((ty, DefKind::AssocTy, did));
20632057
}
20642058
}
20652059

@@ -2202,6 +2196,172 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
22022196
Ok((ty, DefKind::AssocTy, assoc_ty_did))
22032197
}
22042198

2199+
fn lookup_inherent_assoc_ty(
2200+
&self,
2201+
name: Ident,
2202+
segment: &hir::PathSegment<'_>,
2203+
adt_did: DefId,
2204+
self_ty: Ty<'tcx>,
2205+
block: hir::HirId,
2206+
span: Span,
2207+
) -> Result<Option<(Ty<'tcx>, DefId)>, ErrorGuaranteed> {
2208+
let tcx = self.tcx();
2209+
2210+
let candidates: Vec<_> = tcx
2211+
.inherent_impls(adt_did)
2212+
.iter()
2213+
.filter_map(|&impl_| Some((impl_, self.lookup_assoc_ty_unchecked(name, block, impl_)?)))
2214+
.collect();
2215+
2216+
if candidates.is_empty() {
2217+
return Ok(None);
2218+
}
2219+
2220+
// In contexts that have no inference context, just make a new one.
2221+
// We do need a local variable to store it, though.
2222+
let infcx_;
2223+
let infcx = match self.infcx() {
2224+
Some(infcx) => infcx,
2225+
None => {
2226+
assert!(!self_ty.needs_infer());
2227+
infcx_ = tcx.infer_ctxt().ignoring_regions().build();
2228+
&infcx_
2229+
}
2230+
};
2231+
2232+
let param_env = tcx.param_env(block.owner.to_def_id());
2233+
let cause = ObligationCause::misc(span, block.owner.def_id);
2234+
let mut fulfillment_errors = Vec::new();
2235+
let mut applicable_candidates: Vec<_> = candidates
2236+
.iter()
2237+
.filter_map(|&(impl_, (assoc_item, def_scope))| {
2238+
infcx.probe(|_| {
2239+
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
2240+
2241+
let impl_ty = tcx.type_of(impl_);
2242+
let impl_substs = infcx.fresh_item_substs(impl_);
2243+
let impl_ty = impl_ty.subst(tcx, impl_substs);
2244+
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
2245+
2246+
// Check that the Self-types can be related.
2247+
// FIXME(fmease): Should we use `eq` here?
2248+
ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
2249+
2250+
// Check whether the impl imposes obligations we have to worry about.
2251+
let impl_bounds = tcx.predicates_of(impl_);
2252+
let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
2253+
2254+
let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
2255+
2256+
let impl_obligations = traits::predicates_for_generics(
2257+
|_, _| cause.clone(),
2258+
param_env,
2259+
impl_bounds,
2260+
);
2261+
2262+
ocx.register_obligations(impl_obligations);
2263+
2264+
let mut errors = ocx.select_where_possible();
2265+
if !errors.is_empty() {
2266+
fulfillment_errors.append(&mut errors);
2267+
return None;
2268+
}
2269+
2270+
// FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot.
2271+
Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs)))
2272+
})
2273+
})
2274+
.collect();
2275+
2276+
if applicable_candidates.len() > 1 {
2277+
return Err(self.complain_about_ambiguous_inherent_assoc_type(
2278+
name,
2279+
applicable_candidates.into_iter().map(|(candidate, ..)| candidate).collect(),
2280+
span,
2281+
));
2282+
}
2283+
2284+
if let Some((assoc_item, def_scope, impl_substs)) = applicable_candidates.pop() {
2285+
self.check_assoc_ty(assoc_item, name, def_scope, block, span);
2286+
2287+
// FIXME(inherent_associated_types): To fully *confirm* the *probed* candidate, we still
2288+
// need to relate the Self-type with fresh item substs & register region obligations for
2289+
// regionck to prove/disprove.
2290+
2291+
let item_substs =
2292+
self.create_substs_for_associated_item(span, assoc_item, segment, impl_substs);
2293+
2294+
// FIXME(fmease, #106722): Check if the bounds on the parameters of the
2295+
// associated type hold, if any.
2296+
let ty = tcx.type_of(assoc_item).subst(tcx, item_substs);
2297+
2298+
return Ok(Some((ty, assoc_item)));
2299+
}
2300+
2301+
Err(self.complain_about_inherent_assoc_type_not_found(
2302+
name,
2303+
self_ty,
2304+
candidates,
2305+
fulfillment_errors,
2306+
span,
2307+
))
2308+
}
2309+
2310+
fn lookup_assoc_ty(
2311+
&self,
2312+
name: Ident,
2313+
block: hir::HirId,
2314+
span: Span,
2315+
scope: DefId,
2316+
) -> Option<DefId> {
2317+
let (item, def_scope) = self.lookup_assoc_ty_unchecked(name, block, scope)?;
2318+
self.check_assoc_ty(item, name, def_scope, block, span);
2319+
Some(item)
2320+
}
2321+
2322+
fn lookup_assoc_ty_unchecked(
2323+
&self,
2324+
name: Ident,
2325+
block: hir::HirId,
2326+
scope: DefId,
2327+
) -> Option<(DefId, DefId)> {
2328+
let tcx = self.tcx();
2329+
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(name, scope, block);
2330+
2331+
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
2332+
// of calling `find_by_name_and_kind`.
2333+
let item = tcx.associated_items(scope).in_definition_order().find(|i| {
2334+
i.kind.namespace() == Namespace::TypeNS
2335+
&& i.ident(tcx).normalize_to_macros_2_0() == ident
2336+
})?;
2337+
2338+
Some((item.def_id, def_scope))
2339+
}
2340+
2341+
fn check_assoc_ty(
2342+
&self,
2343+
item: DefId,
2344+
name: Ident,
2345+
def_scope: DefId,
2346+
block: hir::HirId,
2347+
span: Span,
2348+
) {
2349+
let tcx = self.tcx();
2350+
let kind = DefKind::AssocTy;
2351+
2352+
if !tcx.visibility(item).is_accessible_from(def_scope, tcx) {
2353+
let kind = kind.descr(item);
2354+
let msg = format!("{kind} `{name}` is private");
2355+
let def_span = tcx.def_span(item);
2356+
tcx.sess
2357+
.struct_span_err_with_code(span, &msg, rustc_errors::error_code!(E0624))
2358+
.span_label(span, &format!("private {kind}"))
2359+
.span_label(def_span, &format!("{kind} defined here"))
2360+
.emit();
2361+
}
2362+
tcx.check_stability(item, Some(block), span, None);
2363+
}
2364+
22052365
fn probe_traits_that_match_assoc_ty(
22062366
&self,
22072367
qself_ty: Ty<'tcx>,
@@ -2255,39 +2415,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
22552415
.collect()
22562416
}
22572417

2258-
fn lookup_assoc_ty(
2259-
&self,
2260-
ident: Ident,
2261-
block: hir::HirId,
2262-
span: Span,
2263-
scope: DefId,
2264-
) -> Option<DefId> {
2265-
let tcx = self.tcx();
2266-
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, block);
2267-
2268-
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
2269-
// of calling `find_by_name_and_kind`.
2270-
let item = tcx.associated_items(scope).in_definition_order().find(|i| {
2271-
i.kind.namespace() == Namespace::TypeNS
2272-
&& i.ident(tcx).normalize_to_macros_2_0() == ident
2273-
})?;
2274-
2275-
let kind = DefKind::AssocTy;
2276-
if !item.visibility(tcx).is_accessible_from(def_scope, tcx) {
2277-
let kind = kind.descr(item.def_id);
2278-
let msg = format!("{kind} `{ident}` is private");
2279-
let def_span = self.tcx().def_span(item.def_id);
2280-
tcx.sess
2281-
.struct_span_err_with_code(span, &msg, rustc_errors::error_code!(E0624))
2282-
.span_label(span, &format!("private {kind}"))
2283-
.span_label(def_span, &format!("{kind} defined here"))
2284-
.emit();
2285-
}
2286-
tcx.check_stability(item.def_id, Some(block), span, None);
2287-
2288-
Some(item.def_id)
2289-
}
2290-
22912418
fn qpath_to_ty(
22922419
&self,
22932420
span: Span,
@@ -3375,3 +3502,36 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
33753502
}
33763503
}
33773504
}
3505+
3506+
pub trait InferCtxtExt<'tcx> {
3507+
fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx>;
3508+
}
3509+
3510+
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
3511+
fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx> {
3512+
InternalSubsts::for_item(self.tcx, def_id, |param, _| match param.kind {
3513+
GenericParamDefKind::Lifetime => self.tcx.lifetimes.re_erased.into(),
3514+
GenericParamDefKind::Type { .. } => self
3515+
.next_ty_var(TypeVariableOrigin {
3516+
kind: TypeVariableOriginKind::SubstitutionPlaceholder,
3517+
span: self.tcx.def_span(def_id),
3518+
})
3519+
.into(),
3520+
GenericParamDefKind::Const { .. } => {
3521+
let span = self.tcx.def_span(def_id);
3522+
let origin = ConstVariableOrigin {
3523+
kind: ConstVariableOriginKind::SubstitutionPlaceholder,
3524+
span,
3525+
};
3526+
self.next_const_var(
3527+
self.tcx
3528+
.type_of(param.def_id)
3529+
.no_bound_vars()
3530+
.expect("const parameter types cannot be generic"),
3531+
origin,
3532+
)
3533+
.into()
3534+
}
3535+
})
3536+
}
3537+
}

‎compiler/rustc_hir_typeck/src/method/probe.rs

+1-29
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ use rustc_data_structures::fx::FxHashSet;
99
use rustc_errors::Applicability;
1010
use rustc_hir as hir;
1111
use rustc_hir::def::DefKind;
12+
use rustc_hir_analysis::astconv::InferCtxtExt as _;
1213
use rustc_hir_analysis::autoderef::{self, Autoderef};
1314
use rustc_infer::infer::canonical::OriginalQueryValues;
1415
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
15-
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1616
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
17-
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
1817
use rustc_middle::middle::stability;
1918
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
2019
use rustc_middle::ty::AssocItem;
@@ -1941,33 +1940,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
19411940
(self.tcx.type_of(impl_def_id), self.fresh_item_substs(impl_def_id))
19421941
}
19431942

1944-
fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx> {
1945-
InternalSubsts::for_item(self.tcx, def_id, |param, _| match param.kind {
1946-
GenericParamDefKind::Lifetime => self.tcx.lifetimes.re_erased.into(),
1947-
GenericParamDefKind::Type { .. } => self
1948-
.next_ty_var(TypeVariableOrigin {
1949-
kind: TypeVariableOriginKind::SubstitutionPlaceholder,
1950-
span: self.tcx.def_span(def_id),
1951-
})
1952-
.into(),
1953-
GenericParamDefKind::Const { .. } => {
1954-
let span = self.tcx.def_span(def_id);
1955-
let origin = ConstVariableOrigin {
1956-
kind: ConstVariableOriginKind::SubstitutionPlaceholder,
1957-
span,
1958-
};
1959-
self.next_const_var(
1960-
self.tcx
1961-
.type_of(param.def_id)
1962-
.no_bound_vars()
1963-
.expect("const parameter types cannot be generic"),
1964-
origin,
1965-
)
1966-
.into()
1967-
}
1968-
})
1969-
}
1970-
19711943
/// Replaces late-bound-regions bound by `value` with `'static` using
19721944
/// `ty::erase_late_bound_regions`.
19731945
///
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![feature(inherent_associated_types)]
2+
#![allow(incomplete_features)]
3+
4+
struct Wrapper<T>(T);
5+
6+
impl Wrapper<i32> {
7+
type Foo = i32;
8+
}
9+
10+
impl Wrapper<()> {
11+
type Foo = ();
12+
}
13+
14+
fn main() {
15+
let _: Wrapper<_>::Foo = (); //~ ERROR multiple applicable items in scope
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0034]: multiple applicable items in scope
2+
--> $DIR/ambiguity.rs:15:24
3+
|
4+
LL | let _: Wrapper<_>::Foo = ();
5+
| ^^^ multiple `Foo` found
6+
|
7+
note: candidate #1 is defined in an impl for the type `Wrapper<i32>`
8+
--> $DIR/ambiguity.rs:7:5
9+
|
10+
LL | type Foo = i32;
11+
| ^^^^^^^^
12+
note: candidate #2 is defined in an impl for the type `Wrapper<()>`
13+
--> $DIR/ambiguity.rs:11:5
14+
|
15+
LL | type Foo = ();
16+
| ^^^^^^^^
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0034`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// known-bug: unknown
2+
// failure-status: 101
3+
// normalize-stderr-test "note: .*\n\n" -> ""
4+
// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
5+
// rustc-env:RUST_BACKTRACE=0
6+
7+
// FIXME: I presume a type variable that couldn't be solved by `resolve_vars_if_possible`
8+
// escapes the InferCtxt snapshot.
9+
10+
#![feature(inherent_associated_types)]
11+
#![allow(incomplete_features)]
12+
13+
struct Cont<T>(T);
14+
15+
impl<T: Copy> Cont<T> {
16+
type Out = Vec<T>;
17+
}
18+
19+
pub fn weird<T: Copy>(x: T) {
20+
let _: Cont<_>::Out = vec![true];
21+
}
22+
23+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
error: the compiler unexpectedly panicked. this is a bug.
2+
3+
query stack during panic:
4+
#0 [typeck] type-checking `weird`
5+
#1 [typeck_item_bodies] type-checking all item bodies
6+
end of query stack
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// known-bug: unknown
2+
3+
#![feature(inherent_associated_types)]
4+
#![allow(incomplete_features)]
5+
6+
struct S<T>(T);
7+
8+
impl S<()> {
9+
type P = i128;
10+
}
11+
12+
fn main() {
13+
// We fail to infer `_ == ()` here.
14+
let _: S<_>::P;
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/inference-fail.rs:14:14
3+
|
4+
LL | let _: S<_>::P;
5+
| ^ cannot infer type
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0282`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// known-bug: unknown
2+
// check-pass
3+
4+
// We currently don't region-check inherent associated type projections at all.
5+
6+
#![feature(inherent_associated_types)]
7+
#![allow(incomplete_features, dead_code)]
8+
9+
struct S<T>(T);
10+
11+
impl S<&'static ()> {
12+
type T = ();
13+
}
14+
15+
fn usr<'a>() {
16+
let _: S::<&'a ()>::T; // this should *fail* but it doesn't!
17+
}
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// check-pass
2+
3+
#![feature(inherent_associated_types)]
4+
#![allow(incomplete_features)]
5+
6+
// Check that inherent associated types are dispatched on the concrete Self type.
7+
8+
struct Select<T>(T);
9+
10+
impl Select<u8> {
11+
type Projection = ();
12+
}
13+
14+
impl Select<String> {
15+
type Projection = bool;
16+
}
17+
18+
struct Choose<T>(T);
19+
struct NonCopy;
20+
21+
impl<T: Copy> Choose<T> {
22+
type Result = Vec<T>;
23+
}
24+
25+
impl Choose<NonCopy> {
26+
type Result = ();
27+
}
28+
29+
fn main() {
30+
let _: Select<String>::Projection = false;
31+
let _: Select<u8>::Projection = ();
32+
33+
let _: Choose<NonCopy>::Result = ();
34+
let _: Choose<bool>::Result = vec![true];
35+
}
36+
37+
// Test if we use the correct `ParamEnv` when proving obligations.
38+
39+
pub fn parameterized<T: Copy>(x: T) {
40+
let _: Choose<T>::Result = vec![x];
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// check-pass
2+
3+
#![feature(inherent_associated_types, auto_traits, negative_impls)]
4+
#![allow(incomplete_features)]
5+
6+
use std::cmp::Ordering;
7+
8+
// Check that inherent associated types are dispatched on the concrete Self type.
9+
10+
struct Select<T, U>(T, U);
11+
12+
impl<T: Ordinary, U: Ordinary> Select<T, U> {
13+
type Type = ();
14+
}
15+
16+
impl<T: Ordinary> Select<T, Special> {
17+
type Type = bool;
18+
}
19+
20+
impl<T: Ordinary> Select<Special, T> {
21+
type Type = Ordering;
22+
}
23+
24+
impl Select<Special, Special> {
25+
type Type = (bool, bool);
26+
}
27+
28+
fn main() {
29+
let _: Select<String, Special>::Type = false;
30+
let _: Select<Special, Special>::Type = (true, false);
31+
let _: Select<Special, u8>::Type = Ordering::Equal;
32+
let _: Select<i128, ()>::Type = ();
33+
}
34+
35+
enum Special {}
36+
37+
impl !Ordinary for Special {}
38+
39+
auto trait Ordinary {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![feature(inherent_associated_types)]
2+
#![allow(incomplete_features)]
3+
4+
struct Parameterized<T, U>(T, U);
5+
6+
impl Parameterized<(), ()> {
7+
type Output = bool;
8+
}
9+
10+
impl<T> Parameterized<bool, T> {
11+
type Result = T;
12+
}
13+
14+
fn main() {
15+
let _: Parameterized<(), ()>::Output = String::new(); //~ ERROR mismatched types
16+
let _: Parameterized<bool, u32>::Result = (); //~ ERROR mismatched types
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/dispatch-on-self-type-2.rs:15:44
3+
|
4+
LL | let _: Parameterized<(), ()>::Output = String::new();
5+
| ----------------------------- ^^^^^^^^^^^^^ expected `bool`, found `String`
6+
| |
7+
| expected due to this
8+
9+
error[E0308]: mismatched types
10+
--> $DIR/dispatch-on-self-type-2.rs:16:47
11+
|
12+
LL | let _: Parameterized<bool, u32>::Result = ();
13+
| -------------------------------- ^^ expected `u32`, found `()`
14+
| |
15+
| expected due to this
16+
17+
error: aborting due to 2 previous errors
18+
19+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#![feature(inherent_associated_types)]
2+
#![allow(incomplete_features)]
3+
4+
// Check that it's okay to report “[inherent] associated type […] not found” for inherent associated
5+
// type candidates that are not applicable (due to unsuitable Self type) even if there exists a
6+
// “shadowed” associated type from a trait with the same name since its use would be ambiguous
7+
// anyway if the IAT didn't exist.
8+
// FIXME(inherent_associated_types): Figure out which error would be more helpful here.
9+
10+
// revisions: shadowed uncovered
11+
12+
struct S<T>(T);
13+
14+
trait Tr {
15+
type Pr;
16+
}
17+
18+
impl<T> Tr for S<T> {
19+
type Pr = ();
20+
}
21+
22+
#[cfg(shadowed)]
23+
impl S<()> {
24+
type Pr = i32;
25+
}
26+
27+
fn main() {
28+
let _: S::<bool>::Pr = ();
29+
//[shadowed]~^ ERROR associated type `Pr` not found
30+
//[uncovered]~^^ ERROR ambiguous associated type
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0220]: associated type `Pr` not found for `S<bool>` in the current scope
2+
--> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:23
3+
|
4+
LL | struct S<T>(T);
5+
| ----------- associated item `Pr` not found for this struct
6+
...
7+
LL | let _: S::<bool>::Pr = ();
8+
| ^^ associated item not found in `S<bool>`
9+
|
10+
= note: the associated type was found for
11+
- `S<()>`
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0220`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0223]: ambiguous associated type
2+
--> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:12
3+
|
4+
LL | let _: S::<bool>::Pr = ();
5+
| ^^^^^^^^^^^^^ help: use the fully-qualified path: `<S<bool> as Tr>::Pr`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0223`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0220]: associated type `Proj` not found for `Family<Option<()>>` in the current scope
2+
--> $DIR/not-found-self-type-differs.rs:17:34
3+
|
4+
LL | struct Family<T>(T);
5+
| ---------------- associated item `Proj` not found for this struct
6+
...
7+
LL | type Alias = Family<Option<()>>::Proj;
8+
| ^^^^ associated item not found in `Family<Option<()>>`
9+
|
10+
= note: the associated type was found for
11+
- `Family<()>`
12+
- `Family<Result<T, ()>>`
13+
14+
error: aborting due to previous error
15+
16+
For more information about this error, try `rustc --explain E0220`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0220]: associated type `Proj` not found for `Family<PathBuf>` in the current scope
2+
--> $DIR/not-found-self-type-differs.rs:21:40
3+
|
4+
LL | struct Family<T>(T);
5+
| ---------------- associated item `Proj` not found for this struct
6+
...
7+
LL | let _: Family<std::path::PathBuf>::Proj = ();
8+
| ^^^^ associated item not found in `Family<PathBuf>`
9+
|
10+
= note: the associated type was found for
11+
- `Family<()>`
12+
- `Family<Result<T, ()>>`
13+
14+
error: aborting due to previous error
15+
16+
For more information about this error, try `rustc --explain E0220`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// revisions: local alias
2+
3+
#![feature(inherent_associated_types)]
4+
#![allow(incomplete_features)]
5+
6+
struct Family<T>(T);
7+
8+
impl Family<()> {
9+
type Proj = ();
10+
}
11+
12+
impl<T> Family<Result<T, ()>> {
13+
type Proj = Self;
14+
}
15+
16+
#[cfg(alias)]
17+
type Alias = Family<Option<()>>::Proj; //[alias]~ ERROR associated type `Proj` not found for `Family<Option<()>>`
18+
19+
fn main() {
20+
#[cfg(local)]
21+
let _: Family<std::path::PathBuf>::Proj = (); //[local]~ ERROR associated type `Proj` not found for `Family<PathBuf>`
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Regression test for issue #104251.
2+
3+
#![feature(inherent_associated_types)]
4+
#![allow(incomplete_features)]
5+
6+
struct Container<T: ?Sized>(T);
7+
8+
impl<T> Container<T> {
9+
type Yield = i32;
10+
}
11+
12+
struct Duple<T, U>(T, U);
13+
14+
impl<T: Copy, U: Send> Duple<T, U> {
15+
type Combination = (T, U);
16+
}
17+
18+
fn main() {
19+
let _: Container<[u8]>::Yield = 1; //~ ERROR the associated type `Yield` exists for `Container<[u8]>`, but its trait bounds were not satisfied
20+
let _: Duple<String, std::rc::Rc<str>>::Combination; //~ ERROR the associated type `Combination` exists for `Duple<String, Rc<str>>`, but its trait bounds were not satisfied
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error: the associated type `Yield` exists for `Container<[u8]>`, but its trait bounds were not satisfied
2+
--> $DIR/not-found-unsatisfied-bounds-0.rs:19:29
3+
|
4+
LL | struct Container<T: ?Sized>(T);
5+
| --------------------------- associated item `Yield` not found for this struct
6+
...
7+
LL | let _: Container<[u8]>::Yield = 1;
8+
| ^^^^^ associated type cannot be referenced on `Container<[u8]>` due to unsatisfied trait bounds
9+
|
10+
= note: the following trait bounds were not satisfied:
11+
`[u8]: Sized`
12+
13+
error: the associated type `Combination` exists for `Duple<String, Rc<str>>`, but its trait bounds were not satisfied
14+
--> $DIR/not-found-unsatisfied-bounds-0.rs:20:45
15+
|
16+
LL | struct Duple<T, U>(T, U);
17+
| ------------------ associated item `Combination` not found for this struct
18+
...
19+
LL | let _: Duple<String, std::rc::Rc<str>>::Combination;
20+
| ^^^^^^^^^^^ associated type cannot be referenced on `Duple<String, Rc<str>>` due to unsatisfied trait bounds
21+
|
22+
= note: the following trait bounds were not satisfied:
23+
`Rc<str>: Send`
24+
`String: Copy`
25+
26+
error: aborting due to 2 previous errors
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// fail-check
2+
3+
#![feature(inherent_associated_types)]
4+
#![allow(incomplete_features)]
5+
6+
// Test if we use the correct `ParamEnv` when proving obligations.
7+
8+
fn parameterized<T>() {
9+
let _: Container<T>::Proj = String::new(); //~ ERROR the associated type `Proj` exists for `Container<T>`, but its trait bounds were not satisfied
10+
}
11+
12+
struct Container<T>(T);
13+
14+
impl<T: Clone> Container<T> {
15+
type Proj = String;
16+
}
17+
18+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: the associated type `Proj` exists for `Container<T>`, but its trait bounds were not satisfied
2+
--> $DIR/not-found-unsatisfied-bounds-1.rs:9:26
3+
|
4+
LL | let _: Container<T>::Proj = String::new();
5+
| ^^^^ associated type cannot be referenced on `Container<T>` due to unsatisfied trait bounds
6+
...
7+
LL | struct Container<T>(T);
8+
| ------------------- associated item `Proj` not found for this struct
9+
|
10+
= note: the following trait bounds were not satisfied:
11+
`T: Clone`
12+
13+
error: aborting due to previous error
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![feature(inherent_associated_types)]
2+
#![allow(incomplete_features)]
3+
4+
struct S<A, B>(A, B);
5+
struct Featureless;
6+
7+
trait One {}
8+
trait Two {}
9+
10+
impl<T: One> S<Featureless, T> {
11+
type X = ();
12+
}
13+
14+
impl<T: Two> S<T, Featureless> {
15+
type X = String;
16+
}
17+
18+
fn main() {
19+
let _: S::<Featureless, Featureless>::X; //~ ERROR the associated type `X` exists for `S<Featureless, Featureless>`, but its trait bounds were not satisfied
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: the associated type `X` exists for `S<Featureless, Featureless>`, but its trait bounds were not satisfied
2+
--> $DIR/not-found-unsatisfied-bounds-in-multiple-impls.rs:19:43
3+
|
4+
LL | struct S<A, B>(A, B);
5+
| -------------- associated item `X` not found for this struct
6+
LL | struct Featureless;
7+
| ------------------
8+
| |
9+
| doesn't satisfy `Featureless: One`
10+
| doesn't satisfy `Featureless: Two`
11+
...
12+
LL | let _: S::<Featureless, Featureless>::X;
13+
| ^ associated type cannot be referenced on `S<Featureless, Featureless>` due to unsatisfied trait bounds
14+
|
15+
= note: the following trait bounds were not satisfied:
16+
`Featureless: One`
17+
`Featureless: Two`
18+
19+
error: aborting due to previous error
20+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Regression test for issue #105305 and for
2+
// https://github.com/rust-lang/rust/issues/107468#issuecomment-1409096700
3+
4+
#![feature(inherent_associated_types)]
5+
#![allow(incomplete_features)]
6+
7+
struct S<T>(T);
8+
9+
impl<T, 'a> S<T> { //~ ERROR lifetime parameters must be declared prior to type and const parameters
10+
type P = T;
11+
}
12+
13+
struct Subj<T>(T);
14+
15+
impl<T, S> Subj<(T, S)> {
16+
type Un = (T, S);
17+
}
18+
19+
fn main() {
20+
type A = S<()>::P;
21+
22+
let _: Subj<(i32, i32)>::Un = 0i32; //~ ERROR mismatched types
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: lifetime parameters must be declared prior to type and const parameters
2+
--> $DIR/substitute-params-bad.rs:9:9
3+
|
4+
LL | impl<T, 'a> S<T> {
5+
| ----^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T>`
6+
7+
error[E0308]: mismatched types
8+
--> $DIR/substitute-params-bad.rs:22:35
9+
|
10+
LL | let _: Subj<(i32, i32)>::Un = 0i32;
11+
| -------------------- ^^^^ expected `(i32, i32)`, found `i32`
12+
| |
13+
| expected due to this
14+
|
15+
= note: expected tuple `(i32, i32)`
16+
found type `i32`
17+
18+
error: aborting due to 2 previous errors
19+
20+
For more information about this error, try `rustc --explain E0308`.

‎tests/ui/associated-inherent-types/struct-generics.rs renamed to ‎tests/ui/associated-inherent-types/substitute-params.rs

+8
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@ impl<T> S<T> {
99
type P = T;
1010
}
1111

12+
impl<T> S<(T,)> {
13+
type Un = T;
14+
}
15+
1216
fn main() {
17+
// Regression test for issue #104240.
1318
type A = S<()>::P;
1419
let _: A = ();
20+
21+
// Regression test for issue #107468.
22+
let _: S<(i32,)>::Un = 0i32;
1523
}

0 commit comments

Comments
 (0)
Please sign in to comment.