1
Fork 0

Rollup merge of #107100 - compiler-errors:issue-107087, r=lcnr

Use proper `InferCtxt` when probing for associated types in astconv

Fixes #107087
This commit is contained in:
Matthias Krüger 2023-01-28 05:20:16 +01:00 committed by GitHub
commit 28188d17ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 97 additions and 46 deletions

View file

@ -27,7 +27,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _}; use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::GenericParamDefKind;
@ -37,7 +37,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, Span}; use rustc_span::{sym, Span, DUMMY_SP};
use rustc_target::spec::abi; use rustc_target::spec::abi;
use rustc_trait_selection::traits; use rustc_trait_selection::traits;
use rustc_trait_selection::traits::astconv_object_safety_violations; use rustc_trait_selection::traits::astconv_object_safety_violations;
@ -54,7 +54,7 @@ use std::slice;
pub struct PathSeg(pub DefId, pub usize); pub struct PathSeg(pub DefId, pub usize);
pub trait AstConv<'tcx> { pub trait AstConv<'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; fn tcx(&self) -> TyCtxt<'tcx>;
fn item_def_id(&self) -> DefId; fn item_def_id(&self) -> DefId;
@ -131,6 +131,8 @@ pub trait AstConv<'tcx> {
{ {
self self
} }
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
} }
#[derive(Debug)] #[derive(Debug)]
@ -2132,48 +2134,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) )
.emit() // Already reported in an earlier stage. .emit() // Already reported in an earlier stage.
} else { } else {
// Find all the `impl`s that `qself_ty` has for any trait that has the let traits: Vec<_> =
// associated type, so that we suggest the right one. self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
let infcx = tcx.infer_ctxt().build();
// We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
// to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
let param_env = ty::ParamEnv::empty();
let traits: Vec<_> = self
.tcx()
.all_traits()
.filter(|trait_def_id| {
// Consider only traits with the associated type
tcx.associated_items(*trait_def_id)
.in_definition_order()
.any(|i| {
i.kind.namespace() == Namespace::TypeNS
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
&& matches!(i.kind, ty::AssocKind::Type)
})
// Consider only accessible traits
&& tcx.visibility(*trait_def_id)
.is_accessible_from(self.item_def_id(), tcx)
&& tcx.all_impls(*trait_def_id)
.any(|impl_def_id| {
let trait_ref = tcx.impl_trait_ref(impl_def_id);
trait_ref.map_or(false, |trait_ref| {
let impl_ = trait_ref.subst(
tcx,
infcx.fresh_substs_for_item(span, impl_def_id),
);
infcx
.can_eq(
param_env,
tcx.erase_regions(impl_.self_ty()),
tcx.erase_regions(qself_ty),
)
.is_ok()
})
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
})
})
.map(|trait_def_id| tcx.def_path_str(trait_def_id))
.collect();
// Don't print `TyErr` to the user. // Don't print `TyErr` to the user.
self.report_ambiguous_associated_type( self.report_ambiguous_associated_type(
@ -2232,6 +2194,60 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Ok((ty, DefKind::AssocTy, assoc_ty_did)) Ok((ty, DefKind::AssocTy, assoc_ty_did))
} }
fn probe_traits_that_match_assoc_ty(
&self,
qself_ty: Ty<'tcx>,
assoc_ident: Ident,
) -> Vec<String> {
let tcx = self.tcx();
// In contexts that have no inference context, just make a new one.
// We do need a local variable to store it, though.
let infcx_;
let infcx = if let Some(infcx) = self.infcx() {
infcx
} else {
assert!(!qself_ty.needs_infer());
infcx_ = tcx.infer_ctxt().build();
&infcx_
};
tcx.all_traits()
.filter(|trait_def_id| {
// Consider only traits with the associated type
tcx.associated_items(*trait_def_id)
.in_definition_order()
.any(|i| {
i.kind.namespace() == Namespace::TypeNS
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
&& matches!(i.kind, ty::AssocKind::Type)
})
// Consider only accessible traits
&& tcx.visibility(*trait_def_id)
.is_accessible_from(self.item_def_id(), tcx)
&& tcx.all_impls(*trait_def_id)
.any(|impl_def_id| {
let trait_ref = tcx.impl_trait_ref(impl_def_id);
trait_ref.map_or(false, |trait_ref| {
let impl_ = trait_ref.subst(
tcx,
infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id),
);
infcx
.can_eq(
ty::ParamEnv::empty(),
tcx.erase_regions(impl_.self_ty()),
tcx.erase_regions(qself_ty),
)
.is_ok()
})
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
})
})
.map(|trait_def_id| tcx.def_path_str(trait_def_id))
.collect()
}
fn lookup_assoc_ty( fn lookup_assoc_ty(
&self, &self,
ident: Ident, ident: Ident,

View file

@ -25,7 +25,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericParamKind, Node}; use rustc_hir::{GenericParamKind, Node};
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause; use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
@ -517,6 +517,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) { fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
// There's no place to record types from signatures? // There's no place to record types from signatures?
} }
fn infcx(&self) -> Option<&InferCtxt<'tcx>> {
None
}
} }
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present. /// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.

View file

@ -324,6 +324,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty }; let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty };
self.write_ty(hir_id, ty) self.write_ty(hir_id, ty)
} }
fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
Some(&self.infcx)
}
} }
/// Represents a user-provided type in the raw form (never normalized). /// Represents a user-provided type in the raw form (never normalized).

View file

@ -0,0 +1,18 @@
struct A<T>(T);
trait Foo {
type B;
}
impl Foo for A<u32> {
type B = i32;
}
impl Foo for A<i32> {
type B = i32;
}
fn main() {
A::B::<>::C
//~^ ERROR ambiguous associated type
}

View file

@ -0,0 +1,9 @@
error[E0223]: ambiguous associated type
--> $DIR/issue-107087.rs:16:5
|
LL | A::B::<>::C
| ^^^^^^^^ help: use the fully-qualified path: `<A<_> as Foo>::B`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0223`.