mirror of
https://github.com/rust-lang/rust
synced 2024-10-14 12:33:57 +00:00
Use proper InferCtxt when probing for associated types in astconv
This commit is contained in:
parent
c8e6a9e8b6
commit
da3ecb09d8
|
@ -27,7 +27,7 @@
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
||||
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::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
|
@ -37,7 +37,7 @@
|
|||
use rustc_span::edition::Edition;
|
||||
use rustc_span::lev_distance::find_best_match_for_name;
|
||||
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_trait_selection::traits;
|
||||
use rustc_trait_selection::traits::astconv_object_safety_violations;
|
||||
|
@ -54,7 +54,7 @@
|
|||
pub struct PathSeg(pub DefId, pub usize);
|
||||
|
||||
pub trait AstConv<'tcx> {
|
||||
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
|
||||
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||
|
||||
fn item_def_id(&self) -> DefId;
|
||||
|
||||
|
@ -131,6 +131,8 @@ fn astconv(&self) -> &dyn AstConv<'tcx>
|
|||
{
|
||||
self
|
||||
}
|
||||
|
||||
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -2132,48 +2134,8 @@ pub fn associated_path_to_ty(
|
|||
)
|
||||
.emit() // Already reported in an earlier stage.
|
||||
} else {
|
||||
// Find all the `impl`s that `qself_ty` has for any trait that has the
|
||||
// associated type, so that we suggest the right one.
|
||||
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();
|
||||
let traits: Vec<_> =
|
||||
self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
|
||||
|
||||
// Don't print `TyErr` to the user.
|
||||
self.report_ambiguous_associated_type(
|
||||
|
@ -2232,6 +2194,60 @@ pub fn associated_path_to_ty(
|
|||
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(
|
||||
&self,
|
||||
ident: Ident,
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{GenericParamKind, Node};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
|
@ -517,6 +517,10 @@ fn set_tainted_by_errors(&self, _: ErrorGuaranteed) {
|
|||
fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
|
||||
// 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.
|
||||
|
|
|
@ -324,6 +324,10 @@ fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
|
|||
let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { 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).
|
||||
|
|
18
tests/ui/typeck/issue-107087.rs
Normal file
18
tests/ui/typeck/issue-107087.rs
Normal 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
|
||||
}
|
9
tests/ui/typeck/issue-107087.stderr
Normal file
9
tests/ui/typeck/issue-107087.stderr
Normal 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`.
|
Loading…
Reference in a new issue