mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-25 11:17:13 +00:00
Properly handle normalization
Previously normalization was broken, which caused a lot of fake errors. This fix most type mismatches of the new solver, and it also reverts many test regressions. The downside is that now `chalk_ir::TyKind::AssociatedType`/`chalk_ir::TyKind::Alias` cannot be trusted anymore with their roles, namely: `AssociatedType` is always fully normalized and `Alias` only if it can possibly be normalized further. That seems okay as the new solver does not have this distinction at all (due to it being a lazy normalizer), so this will only hold for the migration time. This does mean we have to change some APIs, notably `hir::Type::walk()` and `TyFingerprint`, to treat `Alias` the same as `AssociatedType`. Another small thing this commit does is to isolate processing of user-written types (currently involving replacing error types and normalizing, but in the future validation will also be needed) to separate functions.
This commit is contained in:
parent
0f1adf43df
commit
287a6e9482
@ -54,6 +54,8 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use stdx::{always, never};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::next_solver::DbInterner;
|
||||
use crate::next_solver::mapping::NextSolverToChalk;
|
||||
use crate::{
|
||||
AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, ImplTraitId, ImplTraitIdx,
|
||||
IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, ParamLoweringMode,
|
||||
@ -922,13 +924,15 @@ impl<'db> InferenceContext<'db> {
|
||||
});
|
||||
diagnostics.shrink_to_fit();
|
||||
for (_, subst) in method_resolutions.values_mut() {
|
||||
*subst = table.resolve_completely(subst.clone());
|
||||
*subst =
|
||||
table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst.clone());
|
||||
*has_errors =
|
||||
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
|
||||
}
|
||||
method_resolutions.shrink_to_fit();
|
||||
for (_, subst) in assoc_resolutions.values_mut() {
|
||||
*subst = table.resolve_completely(subst.clone());
|
||||
*subst =
|
||||
table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst.clone());
|
||||
*has_errors =
|
||||
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
|
||||
}
|
||||
@ -946,7 +950,12 @@ impl<'db> InferenceContext<'db> {
|
||||
result.tuple_field_access_types = tuple_field_accesses_rev
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(idx, subst)| (TupleId(idx as u32), table.resolve_completely(subst)))
|
||||
.map(|(idx, subst)| {
|
||||
(
|
||||
TupleId(idx as u32),
|
||||
table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst),
|
||||
)
|
||||
})
|
||||
.inspect(|(_, subst)| {
|
||||
*has_errors =
|
||||
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
|
||||
@ -1015,14 +1024,12 @@ impl<'db> InferenceContext<'db> {
|
||||
if let Some(self_param) = self.body.self_param
|
||||
&& let Some(ty) = param_tys.next()
|
||||
{
|
||||
let ty = self.insert_type_vars(ty);
|
||||
let ty = self.normalize_associated_types_in(ty);
|
||||
let ty = self.process_user_written_ty(ty);
|
||||
self.write_binding_ty(self_param, ty);
|
||||
}
|
||||
let mut tait_candidates = FxHashSet::default();
|
||||
for (ty, pat) in param_tys.zip(&*self.body.params) {
|
||||
let ty = self.insert_type_vars(ty);
|
||||
let ty = self.normalize_associated_types_in(ty);
|
||||
let ty = self.process_user_written_ty(ty);
|
||||
|
||||
self.infer_top_pat(*pat, &ty, None);
|
||||
if ty
|
||||
@ -1073,7 +1080,7 @@ impl<'db> InferenceContext<'db> {
|
||||
None => self.result.standard_types.unit.clone(),
|
||||
};
|
||||
|
||||
self.return_ty = self.normalize_associated_types_in(return_ty);
|
||||
self.return_ty = self.process_user_written_ty(return_ty);
|
||||
self.return_coercion = Some(CoerceMany::new(self.return_ty.clone()));
|
||||
|
||||
// Functions might be defining usage sites of TAITs.
|
||||
@ -1415,8 +1422,7 @@ impl<'db> InferenceContext<'db> {
|
||||
) -> Ty {
|
||||
let ty = self
|
||||
.with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref));
|
||||
let ty = self.insert_type_vars(ty);
|
||||
self.normalize_associated_types_in(ty)
|
||||
self.process_user_written_ty(ty)
|
||||
}
|
||||
|
||||
fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
|
||||
@ -1562,15 +1568,35 @@ impl<'db> InferenceContext<'db> {
|
||||
ty
|
||||
}
|
||||
|
||||
/// Whenever you lower a user-written type, you should call this.
|
||||
fn process_user_written_ty<T, U>(&mut self, ty: T) -> T
|
||||
where
|
||||
T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'db, U>,
|
||||
U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable<DbInterner<'db>>,
|
||||
{
|
||||
self.table.process_user_written_ty(ty)
|
||||
}
|
||||
|
||||
/// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation,
|
||||
/// while `process_user_written_ty()` should (but doesn't currently).
|
||||
fn process_remote_user_written_ty<T, U>(&mut self, ty: T) -> T
|
||||
where
|
||||
T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'db, U>,
|
||||
U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable<DbInterner<'db>>,
|
||||
{
|
||||
self.table.process_remote_user_written_ty(ty)
|
||||
}
|
||||
|
||||
/// Recurses through the given type, normalizing associated types mentioned
|
||||
/// in it by replacing them by type variables and registering obligations to
|
||||
/// resolve later. This should be done once for every type we get from some
|
||||
/// type annotation (e.g. from a let type annotation, field type or function
|
||||
/// call). `make_ty` handles this already, but e.g. for field types we need
|
||||
/// to do it as well.
|
||||
fn normalize_associated_types_in<T>(&mut self, ty: T) -> T
|
||||
fn normalize_associated_types_in<T, U>(&mut self, ty: T) -> T
|
||||
where
|
||||
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
|
||||
T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'db, U>,
|
||||
U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable<DbInterner<'db>>,
|
||||
{
|
||||
self.table.normalize_associated_types_in(ty)
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ pub(super) struct ClosureSignature {
|
||||
pub(super) expected_sig: FnPointer,
|
||||
}
|
||||
|
||||
impl InferenceContext<'_> {
|
||||
impl<'db> InferenceContext<'db> {
|
||||
pub(super) fn infer_closure(
|
||||
&mut self,
|
||||
body: &ExprId,
|
||||
@ -71,9 +71,13 @@ impl InferenceContext<'_> {
|
||||
None => (None, None),
|
||||
};
|
||||
|
||||
let ClosureSignature { expected_sig: bound_sig, ret_ty: body_ret_ty } =
|
||||
let ClosureSignature { expected_sig: mut bound_sig, ret_ty: body_ret_ty } =
|
||||
self.sig_of_closure(body, ret_type, arg_types, closure_kind, expected_sig);
|
||||
let bound_sig = self.normalize_associated_types_in(bound_sig);
|
||||
bound_sig.substitution.0 = self
|
||||
.normalize_associated_types_in::<_, crate::next_solver::GenericArgs<'db>>(
|
||||
bound_sig.substitution.0,
|
||||
);
|
||||
let bound_sig = bound_sig;
|
||||
let sig_ty = TyKind::Function(bound_sig.clone()).intern(Interner);
|
||||
|
||||
let (id, ty, resume_yield_tys) = match closure_kind {
|
||||
|
@ -1419,7 +1419,7 @@ impl InferenceContext<'_> {
|
||||
None => self.err_ty(),
|
||||
};
|
||||
|
||||
let ret_ty = self.normalize_associated_types_in(ret_ty);
|
||||
let ret_ty = self.process_remote_user_written_ty(ret_ty);
|
||||
|
||||
if self.is_builtin_binop(&lhs_ty, &rhs_ty, op) {
|
||||
// use knowledge of built-in binary ops, which can sometimes help inference
|
||||
@ -1630,8 +1630,7 @@ impl InferenceContext<'_> {
|
||||
Some(match res {
|
||||
Some((field_id, ty)) => {
|
||||
let adjustments = auto_deref_adjust_steps(&autoderef);
|
||||
let ty = self.insert_type_vars(ty);
|
||||
let ty = self.normalize_associated_types_in(ty);
|
||||
let ty = self.process_remote_user_written_ty(ty);
|
||||
|
||||
(ty, field_id, adjustments, true)
|
||||
}
|
||||
@ -1641,8 +1640,7 @@ impl InferenceContext<'_> {
|
||||
let ty = self.db.field_types(field_id.parent)[field_id.local_id]
|
||||
.clone()
|
||||
.substitute(Interner, &subst);
|
||||
let ty = self.insert_type_vars(ty);
|
||||
let ty = self.normalize_associated_types_in(ty);
|
||||
let ty = self.process_remote_user_written_ty(ty);
|
||||
|
||||
(ty, Either::Left(field_id), adjustments, false)
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ impl InferenceContext<'_> {
|
||||
Some(substs) => f.substitute(Interner, substs),
|
||||
None => f.substitute(Interner, &Substitution::empty(Interner)),
|
||||
};
|
||||
self.normalize_associated_types_in(expected_ty)
|
||||
self.process_remote_user_written_ty(expected_ty)
|
||||
}
|
||||
None => self.err_ty(),
|
||||
}
|
||||
@ -152,7 +152,7 @@ impl InferenceContext<'_> {
|
||||
Some(substs) => f.substitute(Interner, substs),
|
||||
None => f.substitute(Interner, &Substitution::empty(Interner)),
|
||||
};
|
||||
self.normalize_associated_types_in(expected_ty)
|
||||
self.process_remote_user_written_ty(expected_ty)
|
||||
}
|
||||
None => {
|
||||
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
|
||||
|
@ -23,7 +23,7 @@ use crate::{
|
||||
|
||||
use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource};
|
||||
|
||||
impl InferenceContext<'_> {
|
||||
impl<'db> InferenceContext<'db> {
|
||||
pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty> {
|
||||
let (value_def, generic_def, substs) = match self.resolve_value_path(path, id)? {
|
||||
ValuePathResolution::GenericDef(value_def, generic_def, substs) => {
|
||||
@ -31,13 +31,13 @@ impl InferenceContext<'_> {
|
||||
}
|
||||
ValuePathResolution::NonGeneric(ty) => return Some(ty),
|
||||
};
|
||||
let substs = self.insert_type_vars(substs);
|
||||
let substs = self.normalize_associated_types_in(substs);
|
||||
let substs =
|
||||
self.process_remote_user_written_ty::<_, crate::next_solver::GenericArgs<'db>>(substs);
|
||||
|
||||
self.add_required_obligations_for_value_path(generic_def, &substs);
|
||||
|
||||
let ty = self.db.value_ty(value_def)?.substitute(Interner, &substs);
|
||||
let ty = self.normalize_associated_types_in(ty);
|
||||
let ty = self.process_remote_user_written_ty(ty);
|
||||
Some(ty)
|
||||
}
|
||||
|
||||
@ -173,14 +173,12 @@ impl InferenceContext<'_> {
|
||||
let last = path.segments().last()?;
|
||||
|
||||
let (ty, orig_ns) = path_ctx.ty_ctx().lower_ty_ext(type_ref);
|
||||
let ty = self.table.insert_type_vars(ty);
|
||||
let ty = self.table.normalize_associated_types_in(ty);
|
||||
let ty = self.table.process_user_written_ty(ty);
|
||||
|
||||
path_ctx.ignore_last_segment();
|
||||
let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns, true);
|
||||
drop_ctx(ctx, no_diagnostics);
|
||||
let ty = self.table.insert_type_vars(ty);
|
||||
let ty = self.table.normalize_associated_types_in(ty);
|
||||
let ty = self.table.process_user_written_ty(ty);
|
||||
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
|
||||
} else {
|
||||
let hygiene = self.body.expr_or_pat_path_hygiene(id);
|
||||
@ -223,8 +221,7 @@ impl InferenceContext<'_> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let ty = self.insert_type_vars(ty);
|
||||
let ty = self.normalize_associated_types_in(ty);
|
||||
let ty = self.process_user_written_ty(ty);
|
||||
|
||||
self.resolve_ty_assoc_item(ty, last_segment.name, id)
|
||||
}
|
||||
|
@ -12,12 +12,14 @@ use hir_expand::name::Name;
|
||||
use intern::sym;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustc_next_trait_solver::solve::HasChanged;
|
||||
use rustc_type_ir::inherent::IntoKind;
|
||||
use rustc_type_ir::{
|
||||
AliasRelationDirection, FloatVid, IntVid, TyVid,
|
||||
inherent::{Span, Term as _},
|
||||
relate::{Relate, solver_relating::RelateExt},
|
||||
solve::{Certainty, NoSolution},
|
||||
};
|
||||
use rustc_type_ir::{TypeSuperFoldable, TypeVisitableExt};
|
||||
use smallvec::SmallVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
@ -31,11 +33,8 @@ use crate::{
|
||||
db::HirDatabase,
|
||||
fold_generic_args, fold_tys_and_consts,
|
||||
next_solver::{
|
||||
self, Binder, DbInterner, ParamEnvAnd, Predicate, PredicateKind, SolverDefIds, Term,
|
||||
infer::{
|
||||
DbInternerInferExt, InferCtxt, canonical::canonicalizer::OriginalQueryValues,
|
||||
snapshot::CombinedSnapshot,
|
||||
},
|
||||
self, Binder, DbInterner, Predicate, PredicateKind, SolverDefIds, Term,
|
||||
infer::{DbInternerInferExt, InferCtxt, snapshot::CombinedSnapshot},
|
||||
mapping::{ChalkToNextSolver, InferenceVarExt, NextSolverToChalk},
|
||||
},
|
||||
to_chalk_trait_id,
|
||||
@ -305,116 +304,21 @@ impl<'a> InferenceTable<'a> {
|
||||
/// type annotation (e.g. from a let type annotation, field type or function
|
||||
/// call). `make_ty` handles this already, but e.g. for field types we need
|
||||
/// to do it as well.
|
||||
#[tracing::instrument(skip(self), ret)]
|
||||
pub(crate) fn normalize_associated_types_in<T>(&mut self, ty: T) -> T
|
||||
pub(crate) fn normalize_associated_types_in<T, U>(&mut self, ty: T) -> T
|
||||
where
|
||||
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
|
||||
T: ChalkToNextSolver<'a, U>,
|
||||
U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable<DbInterner<'a>>,
|
||||
{
|
||||
fold_tys_and_consts(
|
||||
ty,
|
||||
|e, _| match e {
|
||||
Either::Left(ty) => {
|
||||
let ty = self.resolve_ty_shallow(&ty);
|
||||
tracing::debug!(?ty);
|
||||
Either::Left(match ty.kind(Interner) {
|
||||
TyKind::Alias(AliasTy::Projection(proj_ty)) => {
|
||||
let ty = self.normalize_projection_ty(proj_ty.clone());
|
||||
self.resolve_ty_shallow(&ty)
|
||||
}
|
||||
TyKind::AssociatedType(id, subst) => {
|
||||
// return Either::Left(self.resolve_ty_shallow(&ty));
|
||||
if ty.data(Interner).flags.intersects(
|
||||
chalk_ir::TypeFlags::HAS_TY_INFER
|
||||
| chalk_ir::TypeFlags::HAS_CT_INFER,
|
||||
) {
|
||||
return Either::Left(ty);
|
||||
}
|
||||
let var = self.new_type_var();
|
||||
let proj_ty = chalk_ir::ProjectionTy {
|
||||
associated_ty_id: *id,
|
||||
substitution: subst.clone(),
|
||||
};
|
||||
let normalize = chalk_ir::Normalize {
|
||||
alias: AliasTy::Projection(proj_ty),
|
||||
ty: var.clone(),
|
||||
};
|
||||
let goal = chalk_ir::Goal::new(
|
||||
Interner,
|
||||
chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Normalize(
|
||||
normalize,
|
||||
)),
|
||||
);
|
||||
let in_env = InEnvironment::new(&self.trait_env.env, goal);
|
||||
let goal = in_env.to_nextsolver(self.interner);
|
||||
let goal =
|
||||
ParamEnvAnd { param_env: goal.param_env, value: goal.predicate };
|
||||
self.normalize_associated_types_in_ns(ty.to_nextsolver(self.interner))
|
||||
.to_chalk(self.interner)
|
||||
}
|
||||
|
||||
let (canonical_goal, orig_values) = {
|
||||
let mut orig_values = OriginalQueryValues::default();
|
||||
let result =
|
||||
self.infer_ctxt.canonicalize_query(goal, &mut orig_values);
|
||||
(result.canonical, orig_values)
|
||||
};
|
||||
let canonical_goal = rustc_type_ir::Canonical {
|
||||
max_universe: canonical_goal.max_universe,
|
||||
variables: canonical_goal.variables,
|
||||
value: crate::next_solver::Goal {
|
||||
param_env: canonical_goal.value.param_env,
|
||||
predicate: canonical_goal.value.value,
|
||||
},
|
||||
};
|
||||
let solution = next_trait_solve_canonical_in_ctxt(
|
||||
&self.infer_ctxt,
|
||||
canonical_goal,
|
||||
);
|
||||
if let NextTraitSolveResult::Certain(canonical_subst) = solution {
|
||||
let subst = self.instantiate_canonical(canonical_subst).subst;
|
||||
if subst.len(Interner) != orig_values.var_values.len() {
|
||||
ty
|
||||
} else {
|
||||
let target_ty = var.to_nextsolver(self.interner);
|
||||
subst
|
||||
.iter(Interner)
|
||||
.zip(orig_values.var_values.iter())
|
||||
.find_map(|(new, orig)| {
|
||||
if orig.ty() == Some(target_ty) {
|
||||
Some(new.assert_ty_ref(Interner).clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or(ty)
|
||||
}
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
_ => ty,
|
||||
})
|
||||
}
|
||||
Either::Right(c) => Either::Right(match &c.data(Interner).value {
|
||||
chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
|
||||
crate::ConstScalar::UnevaluatedConst(c_id, subst) => {
|
||||
// FIXME: Ideally here we should do everything that we do with type alias, i.e. adding a variable
|
||||
// and registering an obligation. But it needs chalk support, so we handle the most basic
|
||||
// case (a non associated const without generic parameters) manually.
|
||||
if subst.len(Interner) == 0 {
|
||||
if let Ok(eval) = self.db.const_eval(*c_id, subst.clone(), None) {
|
||||
eval
|
||||
} else {
|
||||
unknown_const(c.data(Interner).ty.clone())
|
||||
}
|
||||
} else {
|
||||
unknown_const(c.data(Interner).ty.clone())
|
||||
}
|
||||
}
|
||||
_ => c,
|
||||
},
|
||||
_ => c,
|
||||
}),
|
||||
},
|
||||
DebruijnIndex::INNERMOST,
|
||||
)
|
||||
pub(crate) fn normalize_associated_types_in_ns<T>(&mut self, ty: T) -> T
|
||||
where
|
||||
T: rustc_type_ir::TypeFoldable<DbInterner<'a>>,
|
||||
{
|
||||
let ty = self.resolve_vars_with_obligations(ty);
|
||||
ty.fold_with(&mut Normalizer { table: self })
|
||||
}
|
||||
|
||||
/// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow
|
||||
@ -476,11 +380,27 @@ impl<'a> InferenceTable<'a> {
|
||||
}
|
||||
|
||||
pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
|
||||
let var = self.new_type_var();
|
||||
let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
|
||||
let obligation: Goal = alias_eq.cast(Interner);
|
||||
self.register_obligation(obligation.to_nextsolver(self.interner));
|
||||
var
|
||||
let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(proj_ty))
|
||||
.intern(Interner)
|
||||
.to_nextsolver(self.interner);
|
||||
self.normalize_alias_ty(ty).to_chalk(self.interner)
|
||||
}
|
||||
|
||||
pub(crate) fn normalize_alias_ty(
|
||||
&mut self,
|
||||
alias: crate::next_solver::Ty<'a>,
|
||||
) -> crate::next_solver::Ty<'a> {
|
||||
let infer_term = self.infer_ctxt.next_ty_var();
|
||||
let obligation = crate::next_solver::Predicate::new(
|
||||
self.interner,
|
||||
crate::next_solver::Binder::dummy(crate::next_solver::PredicateKind::AliasRelate(
|
||||
alias.into(),
|
||||
infer_term.into(),
|
||||
rustc_type_ir::AliasRelationDirection::Equate,
|
||||
)),
|
||||
);
|
||||
self.register_obligation(obligation);
|
||||
self.resolve_vars_with_obligations(infer_term)
|
||||
}
|
||||
|
||||
fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
|
||||
@ -591,9 +511,10 @@ impl<'a> InferenceTable<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
|
||||
pub(crate) fn resolve_completely<T, U>(&mut self, t: T) -> T
|
||||
where
|
||||
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
|
||||
T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'a, U>,
|
||||
U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable<DbInterner<'a>>,
|
||||
{
|
||||
let t = self.resolve_with_fallback(t, &|_, _, d, _| d);
|
||||
let t = self.normalize_associated_types_in(t);
|
||||
@ -1045,6 +966,30 @@ impl<'a> InferenceTable<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whenever you lower a user-written type, you should call this.
|
||||
pub(crate) fn process_user_written_ty<T, U>(&mut self, ty: T) -> T
|
||||
where
|
||||
T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'a, U>,
|
||||
U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable<DbInterner<'a>>,
|
||||
{
|
||||
self.process_remote_user_written_ty(ty)
|
||||
// FIXME: Register a well-formed obligation.
|
||||
}
|
||||
|
||||
/// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation,
|
||||
/// while `process_user_written_ty()` should (but doesn't currently).
|
||||
pub(crate) fn process_remote_user_written_ty<T, U>(&mut self, ty: T) -> T
|
||||
where
|
||||
T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'a, U>,
|
||||
U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable<DbInterner<'a>>,
|
||||
{
|
||||
let ty = self.insert_type_vars(ty);
|
||||
// See https://github.com/rust-lang/rust/blob/cdb45c87e2cd43495379f7e867e3cc15dcee9f93/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs#L487-L495:
|
||||
// Even though the new solver only lazily normalizes usually, here we eagerly normalize so that not everything needs
|
||||
// to normalize before inspecting the `TyKind`.
|
||||
self.normalize_associated_types_in(ty)
|
||||
}
|
||||
|
||||
/// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
|
||||
pub(super) fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
|
||||
let data = c.data(Interner);
|
||||
@ -1319,3 +1264,62 @@ mod resolve {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This expects its input to be resolved.
|
||||
struct Normalizer<'a, 'b> {
|
||||
table: &'a mut InferenceTable<'b>,
|
||||
}
|
||||
|
||||
impl<'db> Normalizer<'_, 'db> {
|
||||
fn normalize_alias_term(
|
||||
&mut self,
|
||||
alias_term: crate::next_solver::Term<'db>,
|
||||
) -> crate::next_solver::Term<'db> {
|
||||
let infer_term = self.table.infer_ctxt.next_term_var_of_kind(alias_term);
|
||||
let obligation = crate::next_solver::Predicate::new(
|
||||
self.table.interner,
|
||||
crate::next_solver::Binder::dummy(crate::next_solver::PredicateKind::AliasRelate(
|
||||
alias_term,
|
||||
infer_term,
|
||||
rustc_type_ir::AliasRelationDirection::Equate,
|
||||
)),
|
||||
);
|
||||
self.table.register_obligation(obligation);
|
||||
let term = self.table.resolve_vars_with_obligations(infer_term);
|
||||
// Now normalize the result, because maybe it contains more aliases.
|
||||
match term {
|
||||
Term::Ty(term) => term.super_fold_with(self).into(),
|
||||
Term::Const(term) => term.super_fold_with(self).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> rustc_type_ir::TypeFolder<DbInterner<'db>> for Normalizer<'_, 'db> {
|
||||
fn cx(&self) -> DbInterner<'db> {
|
||||
self.table.interner
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: crate::next_solver::Ty<'db>) -> crate::next_solver::Ty<'db> {
|
||||
if !ty.has_aliases() {
|
||||
return ty;
|
||||
}
|
||||
|
||||
let crate::next_solver::TyKind::Alias(..) = ty.kind() else {
|
||||
return ty.super_fold_with(self);
|
||||
};
|
||||
// FIXME: Handle escaping bound vars by replacing them with placeholders (relevant to when we handle HRTB only).
|
||||
self.normalize_alias_term(ty.into()).expect_type()
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: crate::next_solver::Const<'db>) -> crate::next_solver::Const<'db> {
|
||||
if !ct.has_aliases() {
|
||||
return ct;
|
||||
}
|
||||
|
||||
let crate::next_solver::ConstKind::Unevaluated(..) = ct.kind() else {
|
||||
return ct.super_fold_with(self);
|
||||
};
|
||||
// FIXME: Handle escaping bound vars by replacing them with placeholders (relevant to when we handle HRTB only).
|
||||
self.normalize_alias_term(ct.into()).expect_const()
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,9 @@ use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
AdtId, AliasTy, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId,
|
||||
GenericArgData, Goal, InEnvironment, Interner, Mutability, Scalar, Substitution,
|
||||
TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind,
|
||||
VariableKind, WhereClause,
|
||||
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData,
|
||||
Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef,
|
||||
TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, VariableKind, WhereClause,
|
||||
autoderef::{self, AutoderefKind},
|
||||
db::HirDatabase,
|
||||
from_chalk_trait_id, from_foreign_def_id,
|
||||
@ -106,8 +105,12 @@ impl TyFingerprint {
|
||||
}
|
||||
}
|
||||
TyKind::AssociatedType(_, _)
|
||||
// FIXME(next-solver): Putting `Alias` here is *probably* incorrect, AFAIK it should return `None`. But this breaks
|
||||
// flyimport, which uses an incorrect but fast method resolution algorithm. Therefore we put it here,
|
||||
// because this function is only called by flyimport, and anyway we should get rid of `TyFingerprint`
|
||||
// and switch to `rustc_type_ir`'s `SimplifiedType`.
|
||||
| TyKind::Alias(_)
|
||||
| TyKind::OpaqueType(_, _)
|
||||
| TyKind::Alias(AliasTy::Opaque(_))
|
||||
| TyKind::FnDef(_, _)
|
||||
| TyKind::Closure(_, _)
|
||||
| TyKind::Coroutine(..)
|
||||
@ -115,8 +118,7 @@ impl TyFingerprint {
|
||||
TyKind::Function(fn_ptr) => {
|
||||
TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32)
|
||||
}
|
||||
TyKind::Alias(_)
|
||||
| TyKind::Placeholder(_)
|
||||
TyKind::Placeholder(_)
|
||||
| TyKind::BoundVar(_)
|
||||
| TyKind::InferenceVar(_, _)
|
||||
| TyKind::Error => return None,
|
||||
@ -908,7 +910,10 @@ fn find_matching_impl(
|
||||
}
|
||||
table.register_obligation(goal.to_nextsolver(table.interner));
|
||||
}
|
||||
Some((impl_.impl_items(db), table.resolve_completely(impl_substs)))
|
||||
Some((
|
||||
impl_.impl_items(db),
|
||||
table.resolve_completely::<_, crate::next_solver::GenericArgs<'_>>(impl_substs),
|
||||
))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ fn expr_macro_def_expanded_in_various_places() {
|
||||
100..119 'for _ ...!() {}': {unknown}
|
||||
100..119 'for _ ...!() {}': &'? mut {unknown}
|
||||
100..119 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
|
||||
100..119 'for _ ...!() {}': Option<<{unknown} as Iterator>::Item>
|
||||
100..119 'for _ ...!() {}': Option<{unknown}>
|
||||
100..119 'for _ ...!() {}': ()
|
||||
100..119 'for _ ...!() {}': ()
|
||||
100..119 'for _ ...!() {}': ()
|
||||
@ -296,7 +296,7 @@ fn expr_macro_rules_expanded_in_various_places() {
|
||||
114..133 'for _ ...!() {}': {unknown}
|
||||
114..133 'for _ ...!() {}': &'? mut {unknown}
|
||||
114..133 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
|
||||
114..133 'for _ ...!() {}': Option<<{unknown} as Iterator>::Item>
|
||||
114..133 'for _ ...!() {}': Option<{unknown}>
|
||||
114..133 'for _ ...!() {}': ()
|
||||
114..133 'for _ ...!() {}': ()
|
||||
114..133 'for _ ...!() {}': ()
|
||||
|
@ -362,12 +362,12 @@ fn diverging_expression_3_break() {
|
||||
140..141 'x': u32
|
||||
149..175 '{ for ...; }; }': u32
|
||||
151..172 'for a ...eak; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
|
||||
151..172 'for a ...eak; }': <{unknown} as IntoIterator>::IntoIter
|
||||
151..172 'for a ...eak; }': {unknown}
|
||||
151..172 'for a ...eak; }': !
|
||||
151..172 'for a ...eak; }': <{unknown} as IntoIterator>::IntoIter
|
||||
151..172 'for a ...eak; }': &'? mut <{unknown} as IntoIterator>::IntoIter
|
||||
151..172 'for a ...eak; }': {unknown}
|
||||
151..172 'for a ...eak; }': &'? mut {unknown}
|
||||
151..172 'for a ...eak; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
|
||||
151..172 'for a ...eak; }': Option<<{unknown} as Iterator>::Item>
|
||||
151..172 'for a ...eak; }': Option<{unknown}>
|
||||
151..172 'for a ...eak; }': ()
|
||||
151..172 'for a ...eak; }': ()
|
||||
151..172 'for a ...eak; }': ()
|
||||
@ -379,12 +379,12 @@ fn diverging_expression_3_break() {
|
||||
226..227 'x': u32
|
||||
235..253 '{ for ... {}; }': u32
|
||||
237..250 'for a in b {}': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
|
||||
237..250 'for a in b {}': <{unknown} as IntoIterator>::IntoIter
|
||||
237..250 'for a in b {}': {unknown}
|
||||
237..250 'for a in b {}': !
|
||||
237..250 'for a in b {}': <{unknown} as IntoIterator>::IntoIter
|
||||
237..250 'for a in b {}': &'? mut <{unknown} as IntoIterator>::IntoIter
|
||||
237..250 'for a in b {}': {unknown}
|
||||
237..250 'for a in b {}': &'? mut {unknown}
|
||||
237..250 'for a in b {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
|
||||
237..250 'for a in b {}': Option<<{unknown} as Iterator>::Item>
|
||||
237..250 'for a in b {}': Option<{unknown}>
|
||||
237..250 'for a in b {}': ()
|
||||
237..250 'for a in b {}': ()
|
||||
237..250 'for a in b {}': ()
|
||||
@ -395,12 +395,12 @@ fn diverging_expression_3_break() {
|
||||
304..305 'x': u32
|
||||
313..340 '{ for ...; }; }': u32
|
||||
315..337 'for a ...urn; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
|
||||
315..337 'for a ...urn; }': <{unknown} as IntoIterator>::IntoIter
|
||||
315..337 'for a ...urn; }': {unknown}
|
||||
315..337 'for a ...urn; }': !
|
||||
315..337 'for a ...urn; }': <{unknown} as IntoIterator>::IntoIter
|
||||
315..337 'for a ...urn; }': &'? mut <{unknown} as IntoIterator>::IntoIter
|
||||
315..337 'for a ...urn; }': {unknown}
|
||||
315..337 'for a ...urn; }': &'? mut {unknown}
|
||||
315..337 'for a ...urn; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
|
||||
315..337 'for a ...urn; }': Option<<{unknown} as Iterator>::Item>
|
||||
315..337 'for a ...urn; }': Option<{unknown}>
|
||||
315..337 'for a ...urn; }': ()
|
||||
315..337 'for a ...urn; }': ()
|
||||
315..337 'for a ...urn; }': ()
|
||||
|
@ -48,12 +48,12 @@ fn infer_pattern() {
|
||||
83..84 '1': i32
|
||||
86..93 '"hello"': &'static str
|
||||
101..151 'for (e... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
|
||||
101..151 'for (e... }': <{unknown} as IntoIterator>::IntoIter
|
||||
101..151 'for (e... }': {unknown}
|
||||
101..151 'for (e... }': !
|
||||
101..151 'for (e... }': <{unknown} as IntoIterator>::IntoIter
|
||||
101..151 'for (e... }': &'? mut <{unknown} as IntoIterator>::IntoIter
|
||||
101..151 'for (e... }': {unknown}
|
||||
101..151 'for (e... }': &'? mut {unknown}
|
||||
101..151 'for (e... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
|
||||
101..151 'for (e... }': Option<<{unknown} as Iterator>::Item>
|
||||
101..151 'for (e... }': Option<({unknown}, {unknown})>
|
||||
101..151 'for (e... }': ()
|
||||
101..151 'for (e... }': ()
|
||||
101..151 'for (e... }': ()
|
||||
|
@ -268,12 +268,12 @@ fn infer_std_crash_5() {
|
||||
expect![[r#"
|
||||
26..322 '{ ... } }': ()
|
||||
32..320 'for co... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
|
||||
32..320 'for co... }': <{unknown} as IntoIterator>::IntoIter
|
||||
32..320 'for co... }': {unknown}
|
||||
32..320 'for co... }': !
|
||||
32..320 'for co... }': <{unknown} as IntoIterator>::IntoIter
|
||||
32..320 'for co... }': &'? mut <{unknown} as IntoIterator>::IntoIter
|
||||
32..320 'for co... }': {unknown}
|
||||
32..320 'for co... }': &'? mut {unknown}
|
||||
32..320 'for co... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
|
||||
32..320 'for co... }': Option<<{unknown} as Iterator>::Item>
|
||||
32..320 'for co... }': Option<{unknown}>
|
||||
32..320 'for co... }': ()
|
||||
32..320 'for co... }': ()
|
||||
32..320 'for co... }': ()
|
||||
@ -628,7 +628,7 @@ fn issue_4053_diesel_where_clauses() {
|
||||
65..69 'self': Self
|
||||
267..271 'self': Self
|
||||
466..470 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
|
||||
488..522 '{ ... }': <SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> as BoxedDsl<DB>>::Output
|
||||
488..522 '{ ... }': ()
|
||||
498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
|
||||
498..508 'self.order': O
|
||||
498..515 'self.o...into()': dyn QueryFragment<DB> + '?
|
||||
@ -1248,7 +1248,7 @@ fn test() {
|
||||
16..66 'for _ ... }': {unknown}
|
||||
16..66 'for _ ... }': &'? mut {unknown}
|
||||
16..66 'for _ ... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
|
||||
16..66 'for _ ... }': Option<<{unknown} as Iterator>::Item>
|
||||
16..66 'for _ ... }': Option<{unknown}>
|
||||
16..66 'for _ ... }': ()
|
||||
16..66 'for _ ... }': ()
|
||||
16..66 'for _ ... }': ()
|
||||
|
@ -20,7 +20,7 @@ impl<'a> IntoIterator for &'a Grid {
|
||||
"#,
|
||||
expect![[r#"
|
||||
150..154 'self': &'a Grid
|
||||
174..181 '{ }': impl Iterator<Item = &'? ()>
|
||||
174..181 '{ }': impl Iterator<Item = &'a ()>
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2000,7 +2000,7 @@ fn test() {
|
||||
225..360 'match ... }': ()
|
||||
231..239 'Pin::new': fn new<&'? mut |usize| yields i64 -> &'static str>(&'? mut |usize| yields i64 -> &'static str) -> Pin<&'? mut |usize| yields i64 -> &'static str>
|
||||
231..247 'Pin::n...mut g)': Pin<&'? mut |usize| yields i64 -> &'static str>
|
||||
231..262 'Pin::n...usize)': CoroutineState<i64, &'? str>
|
||||
231..262 'Pin::n...usize)': CoroutineState<i64, &'static str>
|
||||
240..246 '&mut g': &'? mut |usize| yields i64 -> &'static str
|
||||
245..246 'g': |usize| yields i64 -> &'static str
|
||||
255..261 '0usize': usize
|
||||
|
@ -4190,8 +4190,6 @@ fn g<P: PointerFamily>(p: <P as PointerFamily>::Pointer<i32>) {
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME(next-solver): Was `&'a T` but now getting error lifetime.
|
||||
// This might be fixed once we migrate into next-solver fully without chalk-ir in lowering.
|
||||
#[test]
|
||||
fn gats_with_impl_trait() {
|
||||
// FIXME: the last function (`fn i()`) is not valid Rust as of this writing because you cannot
|
||||
@ -4215,21 +4213,21 @@ fn f<T>(v: impl Trait) {
|
||||
}
|
||||
fn g<'a, T: 'a>(v: impl Trait<Assoc<T> = &'a T>) {
|
||||
let a = v.get::<T>();
|
||||
//^ &'? T
|
||||
//^ &'a T
|
||||
let a = v.get::<()>();
|
||||
//^ <impl Trait<Assoc<T> = &'a T> as Trait>::Assoc<()>
|
||||
}
|
||||
fn h<'a>(v: impl Trait<Assoc<i32> = &'a i32> + Trait<Assoc<i64> = &'a i64>) {
|
||||
let a = v.get::<i32>();
|
||||
//^ &'? i32
|
||||
//^ &'a i32
|
||||
let a = v.get::<i64>();
|
||||
//^ &'? i64
|
||||
//^ &'a i64
|
||||
}
|
||||
fn i<'a>(v: impl Trait<Assoc<i32> = &'a i32, Assoc<i64> = &'a i64>) {
|
||||
let a = v.get::<i32>();
|
||||
//^ &'? i32
|
||||
//^ &'a i32
|
||||
let a = v.get::<i64>();
|
||||
//^ &'? i64
|
||||
//^ &'a i64
|
||||
}
|
||||
"#,
|
||||
);
|
||||
@ -4259,8 +4257,8 @@ fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) {
|
||||
127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?)
|
||||
164..195 '{ ...f(); }': ()
|
||||
170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?)
|
||||
170..184 'v.get::<i32>()': <dyn Trait<Assoc<i32> = &'a i32> + '? as Trait>::Assoc<i32>
|
||||
170..192 'v.get:...eref()': {unknown}
|
||||
170..184 'v.get::<i32>()': {unknown}
|
||||
170..192 'v.get:...eref()': &'? {unknown}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -4953,7 +4951,7 @@ where
|
||||
"#,
|
||||
expect![[r#"
|
||||
84..86 'de': D
|
||||
135..138 '{ }': <D as Deserializer<'?>>::Error
|
||||
135..138 '{ }': <D as Deserializer<'de>>::Error
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ use hir_expand::{
|
||||
};
|
||||
use hir_ty::{
|
||||
AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
|
||||
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
|
||||
GenericArgData, Interner, ParamKind, ProjectionTy, QuantifiedWhereClause, Scalar, Substitution,
|
||||
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic,
|
||||
ValueTyDefId, WhereClause, all_super_traits, autoderef, check_orphan_rules,
|
||||
consteval::{ConstExt, try_const_usize, unknown_const_as_generic},
|
||||
@ -4973,6 +4973,7 @@ impl<'db> Type<'db> {
|
||||
| TyKind::Tuple(_, substitution)
|
||||
| TyKind::OpaqueType(_, substitution)
|
||||
| TyKind::AssociatedType(_, substitution)
|
||||
| TyKind::Alias(AliasTy::Projection(ProjectionTy { substitution, .. }))
|
||||
| TyKind::FnDef(_, substitution) => {
|
||||
substitution.iter(Interner).filter_map(|x| x.ty(Interner)).any(|ty| go(db, ty))
|
||||
}
|
||||
@ -5819,7 +5820,11 @@ impl<'db> Type<'db> {
|
||||
cb(type_.derived(ty.clone()));
|
||||
walk_substs(db, type_, substs, cb);
|
||||
}
|
||||
TyKind::AssociatedType(_, substs) => {
|
||||
TyKind::AssociatedType(_, substs)
|
||||
| TyKind::Alias(AliasTy::Projection(hir_ty::ProjectionTy {
|
||||
substitution: substs,
|
||||
..
|
||||
})) => {
|
||||
if ty.associated_type_parent_trait(db).is_some() {
|
||||
cb(type_.derived(ty.clone()));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user