Unnamed repository; edit this file 'description' to name the repository.
Provide an `InferCtxt` to `TyLoweringContext`
So that it can create infer vars, instead of inserting them after the fact. We gain: - Accurate spans for the vars. - Being able to distinguish between valid infer vars the user wrote (or implied) and infer vars caused by errors, which should use dummy spans to prevent false diagnostics. See the removed FIXME in incorrect_generics_len.rs. - No need to try and match the infer var to the `TypeRefId` for `type_of_type_placeholder`, which can fail. Instead we just register them when we create the var. Of course, not every context lowering types has an `InferCtxt`, so it's optional.
Chayim Refael Friedman 7 days ago
parent d712cb7 · commit 9fc3180
-rw-r--r--crates/hir-ty/src/infer.rs140
-rw-r--r--crates/hir-ty/src/infer/diagnostics.rs6
-rw-r--r--crates/hir-ty/src/infer/path.rs30
-rw-r--r--crates/hir-ty/src/infer/unify.rs11
-rw-r--r--crates/hir-ty/src/lib.rs29
-rw-r--r--crates/hir-ty/src/lower.rs141
-rw-r--r--crates/hir-ty/src/lower/path.rs118
-rw-r--r--crates/hir-ty/src/method_resolution/confirm.rs7
-rw-r--r--crates/hir-ty/src/next_solver.rs3
-rw-r--r--crates/hir-ty/src/next_solver/infer/mod.rs11
-rw-r--r--crates/hir-ty/src/opaques.rs4
-rw-r--r--crates/hir-ty/src/tests/simple.rs3
-rw-r--r--crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs12
13 files changed, 310 insertions, 205 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 0b16da722e..8aadab6cdb 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -50,7 +50,7 @@ use hir_def::{
layout::Integer,
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature},
- type_ref::{LifetimeRefId, TypeRef, TypeRefId},
+ type_ref::{LifetimeRefId, TypeRefId},
unstable_features::UnstableFeatures,
};
use hir_expand::{mod_path::ModPath, name::Name};
@@ -72,7 +72,6 @@ use crate::{
ImplTraitId, IncorrectGenericsLenKind, InferBodyId, PathLoweringDiagnostic, Span,
TargetFeatures,
closure_analysis::PlaceBase,
- collect_type_inference_vars,
consteval::{create_anon_const, path_to_const},
db::{AnonConstId, GeneralConstId, HirDatabase, InternedOpaqueTyId},
generics::Generics,
@@ -89,7 +88,8 @@ use crate::{
unify::resolve_completely::WriteBackCtxt,
},
lower::{
- ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic,
+ ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, TyLoweringInferVarsCtx,
+ diagnostics::TyLoweringDiagnostic,
},
method_resolution::CandidateId,
next_solver::{
@@ -1613,7 +1613,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
InferenceTyDiagnosticSource::Signature,
ExpressionStoreOwnerId::Signature(id.into()),
LifetimeElisionKind::for_const(self.interner(), id.loc(self.db).container),
- Span::Dummy,
);
self.return_ty = return_ty;
@@ -1626,7 +1625,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
InferenceTyDiagnosticSource::Signature,
ExpressionStoreOwnerId::Signature(id.into()),
LifetimeElisionKind::Elided(self.types.regions.statik),
- Span::Dummy,
);
self.return_ty = return_ty;
@@ -1664,12 +1662,12 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
if let Some(self_param) = self_param
&& let Some(ty) = param_tys.next()
{
- let ty = self.process_user_written_ty(Span::Dummy, ty);
+ let ty = self.process_user_written_ty(ty);
self.write_binding_ty(self_param, ty);
}
for pat in params {
let ty = param_tys.next().unwrap_or_else(|| self.table.next_ty_var(Span::Dummy));
- let ty = self.process_user_written_ty(Span::Dummy, ty);
+ let ty = self.process_user_written_ty(ty);
self.infer_top_pat(*pat, ty, PatOrigin::Param);
}
@@ -1685,7 +1683,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
ctx.lower_ty(return_ty)
},
);
- self.process_user_written_ty(Span::Dummy, return_ty)
+ self.process_user_written_ty(return_ty)
}
None => self.types.types.unit,
};
@@ -1799,10 +1797,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
self.result.type_of_pat.insert(pat, ty.store());
}
- fn write_type_placeholder_ty(&mut self, type_ref: TypeRefId, ty: Ty<'db>) {
- self.result.type_of_type_placeholder.insert(type_ref, ty.store());
- }
-
fn write_binding_ty(&mut self, id: BindingId, ty: Ty<'db>) {
self.result.type_of_binding.insert(id, ty.store());
}
@@ -1834,6 +1828,13 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
lifetime_elision: LifetimeElisionKind<'db>,
f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> R,
) -> R {
+ let infer_vars = match types_source {
+ InferenceTyDiagnosticSource::Body => Some(TyLoweringInferVarsCtx {
+ table: &mut self.table,
+ type_of_placeholder: &mut self.result.type_of_type_placeholder,
+ }),
+ InferenceTyDiagnosticSource::Signature => None,
+ };
let mut ctx = TyLoweringContext::new(
self.db,
&self.resolver,
@@ -1845,6 +1846,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
&self.generics,
lifetime_elision,
self.allow_using_generic_params,
+ infer_vars,
&self.defined_anon_consts,
);
f(&mut ctx)
@@ -1870,30 +1872,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
type_source: InferenceTyDiagnosticSource,
store_owner: ExpressionStoreOwnerId,
lifetime_elision: LifetimeElisionKind<'db>,
- span: Span,
) -> Ty<'db> {
let ty = self.with_ty_lowering(store, type_source, store_owner, lifetime_elision, |ctx| {
ctx.lower_ty(type_ref)
});
- let ty = self.process_user_written_ty(span, ty);
-
- // Record the association from placeholders' TypeRefId to type variables.
- // We only record them if their number matches. This assumes TypeRef::walk and TypeVisitable process the items in the same order.
- let type_variables = collect_type_inference_vars(&ty);
- let mut placeholder_ids = vec![];
- TypeRef::walk(type_ref, store, &mut |type_ref_id, type_ref| {
- if matches!(type_ref, TypeRef::Placeholder) {
- placeholder_ids.push(type_ref_id);
- }
- });
-
- if placeholder_ids.len() == type_variables.len() {
- for (placeholder_id, type_variable) in placeholder_ids.into_iter().zip(type_variables) {
- self.write_type_placeholder_ty(placeholder_id, type_variable);
- }
- }
-
- ty
+ self.process_user_written_ty(ty)
}
pub(crate) fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> {
@@ -1903,7 +1886,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
InferenceTyDiagnosticSource::Body,
self.store_owner,
LifetimeElisionKind::Infer,
- type_ref.into(),
)
}
@@ -1967,14 +1949,14 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
LifetimeElisionKind::Infer,
|ctx| ctx.lower_lifetime(lifetime_ref),
);
- self.insert_type_vars(lt, Span::Dummy)
+ self.insert_type_vars(lt)
}
- fn insert_type_vars<T>(&mut self, ty: T, span: Span) -> T
+ fn insert_type_vars<T>(&mut self, ty: T) -> T
where
T: TypeFoldable<DbInterner<'db>>,
{
- self.table.insert_type_vars(ty, span)
+ self.table.insert_type_vars(ty)
}
/// Attempts to returns the deeply last field of nested structures, but
@@ -2039,8 +2021,8 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
/// Whenever you lower a user-written type, you should call this.
- fn process_user_written_ty(&mut self, span: Span, ty: Ty<'db>) -> Ty<'db> {
- self.table.process_user_written_ty(span, ty)
+ fn process_user_written_ty(&mut self, ty: Ty<'db>) -> Ty<'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,
@@ -2181,6 +2163,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
path: &Path,
value_ns: bool,
) -> (Ty<'db>, Option<VariantId>) {
+ let interner = self.interner();
let mut ctx = TyLoweringContext::new(
self.db,
&self.resolver,
@@ -2192,16 +2175,20 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
&self.generics,
LifetimeElisionKind::Infer,
self.allow_using_generic_params,
+ Some(TyLoweringInferVarsCtx {
+ table: &mut self.table,
+ type_of_placeholder: &mut self.result.type_of_type_placeholder,
+ }),
&self.defined_anon_consts,
);
if let Some(type_anchor) = path.type_anchor() {
let mut segments = path.segments();
if segments.is_empty() {
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
}
let (mut ty, type_ns) = ctx.lower_ty_ext(type_anchor);
- ty = self.table.process_user_written_ty(type_anchor.into(), ty);
+ ty = ctx.expect_table().process_user_written_ty(ty);
if let Some(TypeNs::SelfType(impl_)) = type_ns
&& let Some(trait_ref) = self.db.impl_trait(impl_)
@@ -2213,20 +2200,20 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
.associated_type_by_name(segments.first().unwrap().name)
{
// `<Self>::AssocType`
- let args = self.infcx().fill_rest_fresh_args(
+ let args = ctx.expect_table().infer_ctxt.fill_rest_fresh_args(
node.into(),
assoc_type.into(),
trait_ref.args,
);
let alias = Ty::new_alias(
- self.interner(),
+ interner,
AliasTy::new_from_args(
- self.interner(),
+ interner,
AliasTyKind::Projection { def_id: assoc_type.into() },
args,
),
);
- ty = self.table.try_structurally_resolve_type(node.into(), alias);
+ ty = ctx.expect_table().try_structurally_resolve_type(node.into(), alias);
segments = segments.skip(1);
}
@@ -2242,15 +2229,15 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
segments = segments.skip(1);
variant.into()
} else {
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
}
}
- None => return (self.err_ty(), None),
+ None => return (self.types.types.error, None),
};
if !segments.is_empty() {
// FIXME: Report an error.
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
} else {
return (ty, Some(variant));
}
@@ -2260,33 +2247,34 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
let interner = DbInterner::conjure();
let (resolution, unresolved) = if value_ns {
let Some(res) = path_ctx.resolve_path_in_value_ns(HygieneId::ROOT) else {
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
};
match res {
ResolveValueResult::ValueNs(value) => match value {
ValueNs::EnumVariantId(var) => {
- let args = path_ctx.substs_from_path(var.into(), true, false);
+ let args = path_ctx.substs_from_path(var.into(), true, false, node.into());
drop(ctx);
let ty = self
.db
.ty(var.lookup(self.db).parent.into())
.instantiate(interner, args)
.skip_norm_wip();
- let ty = self.insert_type_vars(ty, Span::Dummy);
+ let ty = self.insert_type_vars(ty);
return (ty, Some(var.into()));
}
ValueNs::StructId(strukt) => {
- let args = path_ctx.substs_from_path(strukt.into(), true, false);
+ let args =
+ path_ctx.substs_from_path(strukt.into(), true, false, node.into());
drop(ctx);
let ty =
self.db.ty(strukt.into()).instantiate(interner, args).skip_norm_wip();
- let ty = self.insert_type_vars(ty, Span::Dummy);
+ let ty = self.insert_type_vars(ty);
return (ty, Some(strukt.into()));
}
ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
_ => {
drop(ctx);
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
}
},
ResolveValueResult::Partial(typens, unresolved) => (typens, Some(unresolved)),
@@ -2294,33 +2282,33 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
} else {
match path_ctx.resolve_path_in_type_ns() {
Some((it, idx)) => (it, idx),
- None => return (self.err_ty(), None),
+ None => return (self.types.types.error, None),
}
};
return match resolution {
TypeNs::AdtId(AdtId::StructId(strukt)) => {
- let args = path_ctx.substs_from_path(strukt.into(), true, false);
+ let args = path_ctx.substs_from_path(strukt.into(), true, false, node.into());
drop(ctx);
let ty = self.db.ty(strukt.into()).instantiate(interner, args).skip_norm_wip();
- let ty = self.insert_type_vars(ty, Span::Dummy);
+ let ty = self.insert_type_vars(ty);
forbid_unresolved_segments(self, (ty, Some(strukt.into())), unresolved)
}
TypeNs::AdtId(AdtId::UnionId(u)) => {
- let args = path_ctx.substs_from_path(u.into(), true, false);
+ let args = path_ctx.substs_from_path(u.into(), true, false, node.into());
drop(ctx);
let ty = self.db.ty(u.into()).instantiate(interner, args).skip_norm_wip();
- let ty = self.insert_type_vars(ty, Span::Dummy);
+ let ty = self.insert_type_vars(ty);
forbid_unresolved_segments(self, (ty, Some(u.into())), unresolved)
}
TypeNs::EnumVariantId(var) => {
- let args = path_ctx.substs_from_path(var.into(), true, false);
+ let args = path_ctx.substs_from_path(var.into(), true, false, node.into());
drop(ctx);
let ty = self
.db
.ty(var.lookup(self.db).parent.into())
.instantiate(interner, args)
.skip_norm_wip();
- let ty = self.insert_type_vars(ty, Span::Dummy);
+ let ty = self.insert_type_vars(ty);
forbid_unresolved_segments(self, (ty, Some(var.into())), unresolved)
}
TypeNs::SelfType(impl_id) => {
@@ -2330,7 +2318,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
drop(ctx);
let Some(mod_path) = path.mod_path() else {
never!("resolver should always resolve lang item paths");
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
};
return self.resolve_variant_on_alias(node, ty, None, mod_path);
};
@@ -2358,7 +2346,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
// We still have unresolved paths, but enum variants never have
// associated types!
// FIXME: Report an error.
- (self.err_ty(), None)
+ (self.types.types.error, None)
};
}
}
@@ -2372,12 +2360,12 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
// `lower_partly_resolved_path()` returns `None` as type namespace unless
// `remaining_segments` is empty, which is never the case here. We don't know
// which namespace the new `ty` is in until normalized anyway.
- (ty, _) = path_ctx.lower_partly_resolved_path(resolution, true);
+ (ty, _) = path_ctx.lower_partly_resolved_path(resolution, true, node.into());
tried_resolving_once = true;
- ty = self.table.process_user_written_ty(node.into(), ty);
+ ty = path_ctx.expect_table().process_user_written_ty(ty);
if ty.is_ty_error() {
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
}
remaining_segments = remaining_segments.skip(1);
@@ -2396,7 +2384,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
TypeNs::TraitId(_) => {
let Some(remaining_idx) = unresolved else {
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
};
let remaining_segments = path.segments().skip(remaining_idx);
@@ -2405,8 +2393,9 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
path_ctx.ignore_last_segment();
}
- let (mut ty, _) = path_ctx.lower_partly_resolved_path(resolution, true);
- ty = self.table.process_user_written_ty(node.into(), ty);
+ let (mut ty, _) =
+ path_ctx.lower_partly_resolved_path(resolution, true, node.into());
+ ty = ctx.expect_table().process_user_written_ty(ty);
if let Some(segment) = remaining_segments.get(1)
&& let Some((AdtId::EnumId(id), _)) = ty.as_adt()
@@ -2419,7 +2408,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
// We still have unresolved paths, but enum variants never have
// associated types!
// FIXME: Report an error.
- (self.err_ty(), None)
+ (self.types.types.error, None)
};
}
}
@@ -2437,27 +2426,28 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
TypeNs::TypeAliasId(it) => {
let Some(mod_path) = path.mod_path() else {
never!("resolver should always resolve lang item paths");
- return (self.err_ty(), None);
+ return (self.types.types.error, None);
};
- let args = path_ctx.substs_from_path_segment(it.into(), true, None, false);
+ let args =
+ path_ctx.substs_from_path_segment(it.into(), true, None, false, node.into());
drop(ctx);
let interner = DbInterner::conjure();
let ty = self.db.ty(it.into()).instantiate(interner, args).skip_norm_wip();
- let ty = self.insert_type_vars(ty, Span::Dummy);
+ let ty = self.insert_type_vars(ty);
self.resolve_variant_on_alias(node, ty, unresolved, mod_path)
}
TypeNs::AdtSelfType(_) => {
// FIXME this could happen in array size expressions, once we're checking them
- (self.err_ty(), None)
+ (self.types.types.error, None)
}
TypeNs::GenericParam(_) => {
// FIXME potentially resolve assoc type
- (self.err_ty(), None)
+ (self.types.types.error, None)
}
TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::ModuleId(_) => {
// FIXME diagnostic
- (self.err_ty(), None)
+ (self.types.types.error, None)
}
};
diff --git a/crates/hir-ty/src/infer/diagnostics.rs b/crates/hir-ty/src/infer/diagnostics.rs
index a08a8a023e..50feab8dd4 100644
--- a/crates/hir-ty/src/infer/diagnostics.rs
+++ b/crates/hir-ty/src/infer/diagnostics.rs
@@ -18,7 +18,7 @@ use crate::{
db::{AnonConstId, HirDatabase},
generics::Generics,
lower::{
- ForbidParamsAfterReason, LifetimeElisionKind, TyLoweringContext,
+ ForbidParamsAfterReason, LifetimeElisionKind, TyLoweringContext, TyLoweringInferVarsCtx,
path::{PathDiagnosticCallback, PathLoweringContext},
},
};
@@ -75,6 +75,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> {
generics: &'a OnceCell<Generics<'db>>,
lifetime_elision: LifetimeElisionKind<'db>,
allow_using_generic_params: bool,
+ infer_vars: Option<TyLoweringInferVarsCtx<'a, 'db>>,
defined_anon_consts: &'a RefCell<ThinVec<AnonConstId>>,
) -> Self {
let mut ctx = TyLoweringContext::new(
@@ -85,7 +86,8 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> {
generic_def,
generics,
lifetime_elision,
- );
+ )
+ .with_infer_vars_behavior(infer_vars);
if !allow_using_generic_params {
ctx.forbid_params_after(0, ForbidParamsAfterReason::AnonConst);
}
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index bc4039ff2e..c5b3d184b1 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -13,7 +13,7 @@ use stdx::never;
use crate::{
InferenceDiagnostic, Span, ValueTyDefId,
infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
- lower::{GenericPredicates, LifetimeElisionKind},
+ lower::{GenericPredicates, LifetimeElisionKind, TyLoweringInferVarsCtx},
method_resolution::{self, CandidateId, MethodError},
next_solver::{
GenericArg, GenericArgs, TraitRef, Ty, Unnormalized, infer::traits::ObligationCause,
@@ -38,7 +38,7 @@ impl<'db> InferenceContext<'_, 'db> {
}
ValuePathResolution::NonGeneric(ty) => return Some((value, ty)),
};
- let args = self.insert_type_vars(substs, id.into());
+ let args = self.insert_type_vars(substs);
self.add_required_obligations_for_value_path(id, generic_def, args);
@@ -117,7 +117,7 @@ impl<'db> InferenceContext<'_, 'db> {
if let Some(last_segment) = last_segment {
path_ctx.set_current_segment(last_segment)
}
- path_ctx.substs_from_path(value_def, true, false)
+ path_ctx.substs_from_path(value_def, true, false, id.into())
})
};
@@ -150,6 +150,10 @@ impl<'db> InferenceContext<'_, 'db> {
&self.generics,
LifetimeElisionKind::Infer,
self.allow_using_generic_params,
+ Some(TyLoweringInferVarsCtx {
+ table: &mut self.table,
+ type_of_placeholder: &mut self.result.type_of_type_placeholder,
+ }),
&self.defined_anon_consts,
);
let mut path_ctx = if no_diagnostics {
@@ -161,12 +165,12 @@ impl<'db> InferenceContext<'_, 'db> {
let last = path.segments().last()?;
let (ty, orig_ns) = path_ctx.ty_ctx().lower_ty_ext(type_ref);
- let ty = self.table.process_user_written_ty(type_ref.into(), ty);
+ let ty = path_ctx.expect_table().process_user_written_ty(ty);
path_ctx.ignore_last_segment();
- let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns, true);
+ let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns, true, id.into());
drop_ctx(ctx, no_diagnostics);
- let ty = self.table.process_user_written_ty(id.into(), 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.store.expr_or_pat_path_hygiene(id);
@@ -191,9 +195,13 @@ impl<'db> InferenceContext<'_, 'db> {
let (resolution, substs) = match (def, is_before_last) {
(TypeNs::TraitId(trait_), true) => {
- let self_ty = self.table.next_ty_var(id.into());
- let trait_ref =
- path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty, true);
+ let self_ty = path_ctx.expect_table().next_ty_var(id.into());
+ let trait_ref = path_ctx.lower_trait_ref_from_resolved_path(
+ trait_,
+ self_ty,
+ true,
+ id.into(),
+ );
drop_ctx(ctx, no_diagnostics);
self.resolve_trait_assoc_item(trait_ref, last_segment, id)
}
@@ -203,13 +211,13 @@ impl<'db> InferenceContext<'_, 'db> {
// should resolve to an associated type of that trait (e.g. `<T
// as Iterator>::Item::default`)
path_ctx.ignore_last_segment();
- let (ty, _) = path_ctx.lower_partly_resolved_path(def, true);
+ let (ty, _) = path_ctx.lower_partly_resolved_path(def, true, id.into());
drop_ctx(ctx, no_diagnostics);
if ty.is_ty_error() {
return None;
}
- let ty = self.process_user_written_ty(id.into(), ty);
+ let ty = self.process_user_written_ty(ty);
self.resolve_ty_assoc_item(ty, last_segment.name, id)
}
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 33311412bf..d3fe38425f 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -442,23 +442,22 @@ impl<'db> InferenceTable<'db> {
}
}
- pub(super) fn insert_type_vars<T>(&mut self, ty: T, span: Span) -> T
+ pub(super) fn insert_type_vars<T>(&mut self, ty: T) -> T
where
T: TypeFoldable<DbInterner<'db>>,
{
- self.infer_ctxt.insert_type_vars(ty, span)
+ self.infer_ctxt.insert_type_vars(ty)
}
/// Whenever you lower a user-written type, you should call this.
- pub(crate) fn process_user_written_ty(&mut self, span: Span, ty: Ty<'db>) -> Ty<'db> {
- let ty = self.insert_type_vars(ty, span);
- self.try_structurally_resolve_type(span, ty)
+ pub(crate) fn process_user_written_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
+ self.process_remote_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).
pub(crate) fn process_remote_user_written_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
- let ty = self.insert_type_vars(ty, Span::Dummy);
+ 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`.
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index dc8b8d6c99..4c80921423 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -502,35 +502,6 @@ where
Vec::from_iter(collector.params)
}
-struct TypeInferenceVarCollector<'db> {
- type_inference_vars: Vec<Ty<'db>>,
-}
-
-impl<'db> rustc_type_ir::TypeVisitor<DbInterner<'db>> for TypeInferenceVarCollector<'db> {
- type Result = ();
-
- fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result {
- use crate::rustc_type_ir::Flags;
- if ty.is_ty_var() {
- self.type_inference_vars.push(ty);
- } else if ty.flags().intersects(rustc_type_ir::TypeFlags::HAS_TY_INFER) {
- ty.super_visit_with(self);
- } else {
- // Fast path: don't visit inner types (e.g. generic arguments) when `flags` indicate
- // that there are no placeholders.
- }
- }
-}
-
-pub fn collect_type_inference_vars<'db, T>(value: &T) -> Vec<Ty<'db>>
-where
- T: ?Sized + rustc_type_ir::TypeVisitable<DbInterner<'db>>,
-{
- let mut collector = TypeInferenceVarCollector { type_inference_vars: vec![] };
- value.visit_with(&mut collector);
- collector.type_inference_vars
-}
-
pub fn known_const_to_ast<'db>(
konst: Const<'db>,
db: &'db dyn HirDatabase,
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 737cfb16f6..61329f6c88 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -39,7 +39,7 @@ use la_arena::{Arena, ArenaMap, Idx};
use path::{PathDiagnosticCallback, PathLoweringContext};
use rustc_abi::ExternAbi;
use rustc_ast_ir::Mutability;
-use rustc_hash::FxHashSet;
+use rustc_hash::{FxHashMap, FxHashSet};
use rustc_type_ir::{
AliasTyKind, BoundVarIndexKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection,
ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, TyKind, TypeFoldable,
@@ -52,16 +52,17 @@ use thin_vec::ThinVec;
use tracing::debug;
use crate::{
- ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
+ ImplTraitId, Span, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
consteval::{create_anon_const, path_to_const},
db::{AnonConstId, GeneralConstId, HirDatabase, InternedOpaqueTyId},
generics::{Generics, SingleGenerics, generics},
+ infer::unify::InferenceTable,
next_solver::{
AliasTy, Binder, BoundExistentialPredicates, Clause, ClauseKind, Clauses, Const, ConstKind,
- DbInterner, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, FnSigKind, FxIndexMap,
- GenericArg, GenericArgs, ParamConst, ParamEnv, PolyFnSig, Predicate, Region, StoredClauses,
- StoredEarlyBinder, StoredGenericArg, StoredGenericArgs, StoredPolyFnSig, StoredTraitRef,
- StoredTy, TraitPredicate, TraitRef, Ty, Tys, Unnormalized, abi::Safety,
+ DbInterner, DefaultAny, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, FnSigKind,
+ FxIndexMap, GenericArg, GenericArgs, ParamConst, ParamEnv, PolyFnSig, Predicate, Region,
+ StoredClauses, StoredEarlyBinder, StoredGenericArg, StoredGenericArgs, StoredPolyFnSig,
+ StoredTraitRef, StoredTy, TraitPredicate, TraitRef, Ty, Tys, Unnormalized, abi::Safety,
util::BottomUpFolder,
},
};
@@ -184,7 +185,12 @@ pub(crate) enum ForbidParamsAfterReason {
ConstParamTy,
}
-#[derive(Debug)]
+pub(crate) struct TyLoweringInferVarsCtx<'a, 'db> {
+ // Technically we can just put an `&InferCtxt` here, but borrowck constraints requires us to put this:
+ pub(crate) table: &'a mut InferenceTable<'db>,
+ pub(crate) type_of_placeholder: &'a mut FxHashMap<TypeRefId, StoredTy>,
+}
+
pub struct TyLoweringContext<'db, 'a> {
pub db: &'db dyn HirDatabase,
interner: DbInterner<'db>,
@@ -204,6 +210,7 @@ pub struct TyLoweringContext<'db, 'a> {
forbid_params_after: Option<u32>,
forbid_params_after_reason: ForbidParamsAfterReason,
pub(crate) defined_anon_consts: ThinVec<AnonConstId>,
+ infer_vars: Option<TyLoweringInferVarsCtx<'a, 'db>>,
}
impl<'db, 'a> TyLoweringContext<'db, 'a> {
@@ -238,6 +245,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
forbid_params_after: None,
forbid_params_after_reason: ForbidParamsAfterReason::AnonConst,
defined_anon_consts: ThinVec::new(),
+ infer_vars: None,
}
}
@@ -278,9 +286,66 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
self.forbid_params_after_reason = reason;
}
+ pub(crate) fn with_infer_vars_behavior(
+ mut self,
+ behavior: Option<TyLoweringInferVarsCtx<'a, 'db>>,
+ ) -> Self {
+ self.infer_vars = behavior;
+ self
+ }
+
pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) {
self.diagnostics.push(TyLoweringDiagnostic { source: type_ref, kind });
}
+
+ #[track_caller]
+ pub(crate) fn expect_table(&mut self) -> &mut InferenceTable<'db> {
+ self.infer_vars.as_mut().unwrap().table
+ }
+
+ fn next_ty_var(&mut self, type_ref: TypeRefId) -> Ty<'db> {
+ match &mut self.infer_vars {
+ Some(infer_vars) => {
+ let var = infer_vars.table.next_ty_var(type_ref.into());
+ infer_vars.type_of_placeholder.insert(type_ref, var.store());
+ var
+ }
+ None => {
+ // FIXME: Emit an error: no infer vars allowed here.
+ self.types.types.error
+ }
+ }
+ }
+
+ fn next_ty_var_no_placeholder(&mut self, span: Span) -> Ty<'db> {
+ match &mut self.infer_vars {
+ Some(infer_vars) => infer_vars.table.next_ty_var(span),
+ None => {
+ // FIXME: Emit an error: no infer vars allowed here.
+ self.types.types.error
+ }
+ }
+ }
+
+ fn next_const_var(&mut self, span: Span) -> Const<'db> {
+ match &mut self.infer_vars {
+ Some(infer_vars) => infer_vars.table.next_const_var(span),
+ None => {
+ // FIXME: Emit an error: no infer vars allowed here.
+ self.types.consts.error
+ }
+ }
+ }
+
+ fn next_region_var(&mut self, span: Span) -> Region<'db> {
+ match &mut self.infer_vars {
+ Some(infer_vars) => infer_vars.table.next_region_var(span),
+ None => {
+ // FIXME: Emit an error: no infer vars allowed here.
+ self.types.regions.error
+ }
+ }
+ }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
@@ -309,7 +374,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
self.resolver,
const_type,
&|| self.generics(),
- None,
+ self.infer_vars.as_ref().map(|vars_ctx| &vars_ctx.table.infer_ctxt),
self.forbid_params_after,
);
@@ -345,7 +410,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
fn type_param(&mut self, id: TypeParamId, index: u32) -> Ty<'db> {
if self.param_index_is_disallowed(index) {
// FIXME: Report an error.
- Ty::new_error(self.interner, ErrorGuaranteed)
+ self.types.types.error
} else {
Ty::new_param(self.interner, id, index)
}
@@ -354,7 +419,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> {
if self.param_index_is_disallowed(index) {
// FIXME: Report an error.
- Region::error(self.interner)
+ self.types.regions.error
} else {
Region::new_early_param(self.interner, EarlyParamRegion { id, index })
}
@@ -391,7 +456,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
}
TypeRef::Array(array) => {
let inner_ty = self.lower_ty(array.ty);
- let const_len = self.lower_const(array.len, Ty::new_usize(interner));
+ let const_len = self.lower_const(array.len, self.types.types.usize);
Ty::new_array_with_const_len(interner, inner_ty, const_len)
}
&TypeRef::Slice(inner) => {
@@ -401,12 +466,11 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
TypeRef::Reference(ref_) => {
let inner_ty = self.lower_ty(ref_.ty);
// FIXME: It should infer the eldided lifetimes instead of stubbing with error
- let lifetime = ref_
- .lifetime
- .map_or_else(|| Region::error(interner), |lr| self.lower_lifetime(lr));
+ let lifetime =
+ ref_.lifetime.map_or(self.types.regions.error, |lr| self.lower_lifetime(lr));
Ty::new_ref(interner, lifetime, inner_ty, lower_mutability(ref_.mutability))
}
- TypeRef::Placeholder => Ty::new_error(interner, ErrorGuaranteed),
+ TypeRef::Placeholder => self.next_ty_var(type_ref_id),
TypeRef::Fn(fn_) => self.lower_fn_ptr(fn_),
TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
TypeRef::ImplTrait(bounds) => {
@@ -462,11 +526,11 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
}
ImplTraitLoweringMode::Disallowed => {
// FIXME: report error
- Ty::new_error(self.interner, ErrorGuaranteed)
+ self.types.types.error
}
}
}
- TypeRef::Error => Ty::new_error(self.interner, ErrorGuaranteed),
+ TypeRef::Error => self.types.types.error,
};
(ty, res)
}
@@ -548,13 +612,13 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
if let Some(type_ref) = path.type_anchor() {
let (ty, res) = self.lower_ty_ext(type_ref);
let mut ctx = self.at_path(path_id);
- return ctx.lower_ty_relative_path(ty, res, false);
+ return ctx.lower_ty_relative_path(ty, res, false, path_id.type_ref().into());
}
let mut ctx = self.at_path(path_id);
let (resolution, remaining_index) = match ctx.resolve_path_in_type_ns() {
Some(it) => it,
- None => return (Ty::new_error(self.interner, ErrorGuaranteed), None),
+ None => return (self.types.types.error, None),
};
if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
@@ -564,7 +628,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
return (ty, None);
}
- ctx.lower_partly_resolved_path(resolution, false)
+ ctx.lower_partly_resolved_path(resolution, false, path_id.type_ref().into())
}
fn lower_trait_ref_from_path(
@@ -578,7 +642,15 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
TypeNs::TraitId(tr) => tr,
_ => return None,
};
- Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx))
+ Some((
+ ctx.lower_trait_ref_from_resolved_path(
+ resolved,
+ explicit_self_ty,
+ false,
+ path_id.type_ref().into(),
+ ),
+ ctx,
+ ))
}
fn lower_trait_ref(
@@ -640,7 +712,10 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
ctx.ty_ctx().unsized_types.insert(self_ty);
} else {
if !ignore_bindings {
- assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref);
+ assoc_bounds = ctx.assoc_type_bindings_from_type_bound(
+ trait_ref,
+ path.type_ref().into(),
+ );
}
clause = Some(Clause(Predicate::new(
interner,
@@ -687,7 +762,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> {
let interner = self.interner;
- let dummy_self_ty = dyn_trait_dummy_self(interner);
+ let dummy_self_ty = self.types.types.dyn_trait_dummy_self;
let mut region = None;
// INVARIANT: The principal trait bound, if present, must come first. Others may be in any
// order but should be in the same order for the same set but possibly different order of
@@ -885,7 +960,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
.map(|arg| {
if arg.walk().any(|arg| arg == dummy_self_ty.into()) {
// FIXME: Report an error.
- Ty::new_error(interner, ErrorGuaranteed).into()
+ self.types.types.error.into()
} else {
arg
}
@@ -911,8 +986,11 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
false
});
if references_self {
- proj.projection_term =
- replace_dummy_self_with_error(interner, proj.projection_term);
+ proj.projection_term = replace_dummy_self_with_error(
+ interner,
+ self.types,
+ proj.projection_term,
+ );
}
ExistentialPredicate::Projection(ExistentialProjection::erase_self_ty(
@@ -950,7 +1028,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
} else {
// FIXME: report error
// (additional non-auto traits, associated type rebound, or no resolved trait)
- Ty::new_error(self.interner, ErrorGuaranteed)
+ self.types.types.error
}
}
@@ -1084,20 +1162,15 @@ impl<T> TyLoweringResult<T> {
}
}
-fn dyn_trait_dummy_self(interner: DbInterner<'_>) -> Ty<'_> {
- // This type must not appear anywhere except here.
- Ty::new_fresh(interner, 0)
-}
-
fn replace_dummy_self_with_error<'db, T: TypeFoldable<DbInterner<'db>>>(
interner: DbInterner<'db>,
+ types: &DefaultAny<'db>,
t: T,
) -> T {
- let dyn_trait_dummy_self = dyn_trait_dummy_self(interner);
t.fold_with(&mut BottomUpFolder {
interner,
ty_op: |ty| {
- if ty == dyn_trait_dummy_self { Ty::new_error(interner, ErrorGuaranteed) } else { ty }
+ if ty == types.types.dyn_trait_dummy_self { types.types.error } else { ty }
},
lt_op: |lt| lt,
ct_op: |ct| ct,
diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs
index 1e7e56ab88..0757d57500 100644
--- a/crates/hir-ty/src/lower/path.rs
+++ b/crates/hir-ty/src/lower/path.rs
@@ -25,9 +25,10 @@ use smallvec::SmallVec;
use crate::{
GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource,
- PathLoweringDiagnostic, TyDefId, ValueTyDefId,
+ PathLoweringDiagnostic, Span, TyDefId, ValueTyDefId,
db::HirDatabase,
generics::{Generics, generics},
+ infer::unify::InferenceTable,
lower::{
AssocTypeShorthandResolution, ForbidParamsAfterReason, GenericPredicateSource,
LifetimeElisionKind, PathDiagnosticCallbackData, const_param_ty,
@@ -83,6 +84,11 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
}
}
+ #[track_caller]
+ pub(crate) fn expect_table(&mut self) -> &mut InferenceTable<'db> {
+ self.ctx.expect_table()
+ }
+
#[inline]
#[cold]
fn on_diagnostic(&mut self, diag: PathLoweringDiagnostic) {
@@ -148,13 +154,14 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
// We need the original resolution to lower `Self::AssocTy` correctly
res: Option<TypeNs>,
infer_args: bool,
+ span: Span,
) -> (Ty<'db>, Option<TypeNs>) {
let remaining_segments = self.segments.len() - self.current_segment_idx;
match remaining_segments {
0 => (ty, res),
1 => {
// resolve unselected assoc types
- (self.select_associated_type(res, infer_args), None)
+ (self.select_associated_type(res, infer_args, span), None)
}
_ => {
// FIXME report error (ambiguous associated type)
@@ -168,6 +175,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
&mut self,
resolution: TypeNs,
infer_args: bool,
+ span: Span,
) -> (Ty<'db>, Option<TypeNs>) {
let remaining_segments = self.segments.skip(self.current_segment_idx + 1);
tracing::debug!(?remaining_segments);
@@ -182,6 +190,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
trait_,
self.ctx.types.types.error,
infer_args,
+ span,
);
tracing::debug!(?trait_ref);
self.skip_resolved_segment();
@@ -202,6 +211,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
infer_args,
None,
true,
+ span,
);
let args = GenericArgs::new_from_iter(
self.ctx.interner,
@@ -249,9 +259,9 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
Ty::new_adt(self.ctx.interner, adt, args)
}
- TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args),
- TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args),
- TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args),
+ TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args, span),
+ TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args, span),
+ TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args, span),
// FIXME: report error
TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => {
return (self.ctx.types.types.error, None);
@@ -261,7 +271,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
tracing::debug!(?ty);
self.skip_resolved_segment();
- self.lower_ty_relative_path(ty, Some(resolution), infer_args)
+ self.lower_ty_relative_path(ty, Some(resolution), infer_args, span)
}
/// This returns whether to keep the resolution (`true`) of throw it (`false`).
@@ -469,7 +479,12 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
}
#[tracing::instrument(skip(self), ret)]
- fn select_associated_type(&mut self, res: Option<TypeNs>, infer_args: bool) -> Ty<'db> {
+ fn select_associated_type(
+ &mut self,
+ res: Option<TypeNs>,
+ infer_args: bool,
+ span: Span,
+ ) -> Ty<'db> {
let interner = self.ctx.interner;
let db = self.ctx.db;
let def = self.ctx.generic_def;
@@ -526,7 +541,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
// generic params. It's inefficient to splice the `Substitution`s, so we may want
// that method to optionally take parent `Substitution` as we already know them at
// this point (`t.substitution`).
- let substs = self.substs_from_path_segment(assoc_type.into(), infer_args, None, true);
+ let substs = self.substs_from_path_segment(assoc_type.into(), infer_args, None, true, span);
let substs = GenericArgs::new_from_iter(
interner,
@@ -536,7 +551,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
Ty::new_projection_from_args(interner, assoc_type.into(), substs)
}
- fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> {
+ fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool, span: Span) -> Ty<'db> {
let generic_def = match typeable {
TyDefId::BuiltinType(builtinty) => {
return Ty::from_builtin_type(self.ctx.interner, builtinty);
@@ -544,7 +559,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
TyDefId::AdtId(it) => it.into(),
TyDefId::TypeAliasId(it) => it.into(),
};
- let args = self.substs_from_path_segment(generic_def, infer_args, None, false);
+ let args = self.substs_from_path_segment(generic_def, infer_args, None, false, span);
let ty = ty_query(self.ctx.db, typeable);
ty.instantiate(self.ctx.interner, args).skip_norm_wip()
}
@@ -559,6 +574,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
resolved: ValueTyDefId,
infer_args: bool,
lowering_assoc_type_generics: bool,
+ span: Span,
) -> GenericArgs<'db> {
let interner = self.ctx.interner;
let prev_current_segment_idx = self.current_segment_idx;
@@ -602,6 +618,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
infer_args,
None,
lowering_assoc_type_generics,
+ span,
);
self.current_segment_idx = prev_current_segment_idx;
self.current_or_prev_segment = prev_current_segment;
@@ -614,6 +631,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
infer_args: bool,
explicit_self_ty: Option<Ty<'db>>,
lowering_assoc_type_generics: bool,
+ span: Span,
) -> GenericArgs<'db> {
let old_lifetime_elision = self.ctx.lifetime_elision;
@@ -654,6 +672,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
PathGenericsSource::Segment(self.current_segment_u32()),
lowering_assoc_type_generics,
self.ctx.lifetime_elision,
+ span,
);
self.ctx.lifetime_elision = old_lifetime_elision;
result
@@ -668,10 +687,12 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
generics_source: PathGenericsSource,
lowering_assoc_type_generics: bool,
lifetime_elision: LifetimeElisionKind<'db>,
+ span: Span,
) -> GenericArgs<'db> {
struct LowererCtx<'a, 'b, 'c, 'db> {
ctx: &'a mut PathLoweringContext<'b, 'c, 'db>,
generics_source: PathGenericsSource,
+ span: Span,
}
impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> {
@@ -734,13 +755,13 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
fn provided_type_like_const(
&mut self,
- _type_ref: TypeRefId,
+ type_ref: TypeRefId,
const_ty: Ty<'db>,
arg: TypeLikeConst<'_>,
) -> Const<'db> {
match arg {
TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty),
- TypeLikeConst::Infer => self.ctx.ctx.types.consts.error,
+ TypeLikeConst::Infer => self.ctx.ctx.next_const_var(type_ref.into()),
}
}
@@ -751,15 +772,18 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
param: GenericParamDataRef<'_>,
infer_args: bool,
preceding_args: &[GenericArg<'db>],
+ had_count_error: bool,
) -> GenericArg<'db> {
let default = || {
self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(|default| {
default.instantiate(self.ctx.ctx.interner, preceding_args).skip_norm_wip()
})
};
+ // If `!infer_args`, we've already emitted an error, so put a dummy span.
+ let span = if !infer_args || had_count_error { Span::Dummy } else { self.span };
match param {
GenericParamDataRef::LifetimeParamData(_) => {
- self.ctx.ctx.types.regions.error.into()
+ self.ctx.ctx.next_region_var(span).into()
}
GenericParamDataRef::TypeParamData(param) => {
if !infer_args
@@ -768,7 +792,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
{
return default;
}
- Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into()
+ self.ctx.ctx.next_ty_var_no_placeholder(span).into()
}
GenericParamDataRef::ConstParamData(param) => {
if !infer_args
@@ -780,7 +804,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
let GenericParamId::ConstParamId(_) = param_id else {
unreachable!("non-const param ID for const param");
};
- self.ctx.ctx.types.consts.error.into()
+ self.ctx.ctx.next_const_var(span).into()
}
}
}
@@ -835,7 +859,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
lifetime_elision,
lowering_assoc_type_generics,
explicit_self_ty,
- &mut LowererCtx { ctx: self, generics_source },
+ &mut LowererCtx { ctx: self, generics_source, span },
)
}
@@ -844,8 +868,9 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
resolved: TraitId,
explicit_self_ty: Ty<'db>,
infer_args: bool,
+ span: Span,
) -> TraitRef<'db> {
- let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args);
+ let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args, span);
TraitRef::new_from_args(self.ctx.interner, resolved.into(), args)
}
@@ -854,13 +879,21 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
resolved: TraitId,
explicit_self_ty: Ty<'db>,
infer_args: bool,
+ span: Span,
) -> GenericArgs<'db> {
- self.substs_from_path_segment(resolved.into(), infer_args, Some(explicit_self_ty), false)
+ self.substs_from_path_segment(
+ resolved.into(),
+ infer_args,
+ Some(explicit_self_ty),
+ false,
+ span,
+ )
}
pub(super) fn assoc_type_bindings_from_type_bound<'c>(
mut self,
trait_ref: TraitRef<'db>,
+ span: Span,
) -> Option<impl Iterator<Item = (Clause<'db>, GenericPredicateSource)> + use<'a, 'b, 'c, 'db>>
{
let interner = self.ctx.interner;
@@ -892,6 +925,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
},
false,
this.ctx.lifetime_elision,
+ span,
)
});
let args = GenericArgs::new_from_iter(
@@ -1011,6 +1045,7 @@ pub(crate) trait GenericArgsLowerer<'db> {
param: GenericParamDataRef<'_>,
infer_args: bool,
preceding_args: &[GenericArg<'db>],
+ had_count_error: bool,
) -> GenericArg<'db>;
fn parent_arg(&mut self, param_idx: u32, param_id: GenericParamId) -> GenericArg<'db>;
@@ -1179,7 +1214,14 @@ pub(crate) fn substs_from_args_and_bindings<'db>(
ctx.provided_kind(self_param_id, self_param, self_ty)
} else {
explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| {
- ctx.inferred_kind(def, self_param_id, self_param, infer_args, &substs)
+ ctx.inferred_kind(
+ def,
+ self_param_id,
+ self_param,
+ infer_args,
+ &substs,
+ had_count_error,
+ )
})
};
params.next();
@@ -1198,7 +1240,14 @@ pub(crate) fn substs_from_args_and_bindings<'db>(
{
// Do not allow specifying `impl Trait` explicitly. We already err at that, but if we won't handle it here
// we will handle it as if it was specified, instead of inferring it.
- substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
+ substs.push(ctx.inferred_kind(
+ def,
+ param_id,
+ param,
+ infer_args,
+ &substs,
+ had_count_error,
+ ));
params.next();
}
(HirGenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_))
@@ -1214,7 +1263,14 @@ pub(crate) fn substs_from_args_and_bindings<'db>(
) => {
// We expected a lifetime argument, but got a type or const
// argument. That means we're inferring the lifetime.
- substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs));
+ substs.push(ctx.inferred_kind(
+ def,
+ param_id,
+ param,
+ infer_args,
+ &substs,
+ had_count_error,
+ ));
params.next();
force_infer_lt = Some((arg_idx as u32, param_id));
}
@@ -1283,7 +1339,14 @@ pub(crate) fn substs_from_args_and_bindings<'db>(
| LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }
| LifetimeElisionKind::AnonymousReportError => {
assert!(had_count_error);
- ctx.inferred_kind(def, param_id, param, infer_args, &substs)
+ ctx.inferred_kind(
+ def,
+ param_id,
+ param,
+ infer_args,
+ &substs,
+ had_count_error,
+ )
}
LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => {
Region::new_static(interner).into()
@@ -1293,11 +1356,18 @@ pub(crate) fn substs_from_args_and_bindings<'db>(
| LifetimeElisionKind::Infer => {
// FIXME: With `AnonymousCreateParameter`, we need to create a new lifetime parameter here
// (but this will probably be done in hir-def lowering instead).
- ctx.inferred_kind(def, param_id, param, infer_args, &substs)
+ ctx.inferred_kind(
+ def,
+ param_id,
+ param,
+ infer_args,
+ &substs,
+ had_count_error,
+ )
}
}
} else {
- ctx.inferred_kind(def, param_id, param, infer_args, &substs)
+ ctx.inferred_kind(def, param_id, param, infer_args, &substs, had_count_error)
};
substs.push(param);
params.next();
diff --git a/crates/hir-ty/src/method_resolution/confirm.rs b/crates/hir-ty/src/method_resolution/confirm.rs
index a3a5a9ca54..c425e69dc5 100644
--- a/crates/hir-ty/src/method_resolution/confirm.rs
+++ b/crates/hir-ty/src/method_resolution/confirm.rs
@@ -427,12 +427,15 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
_def: GenericDefId,
param_id: GenericParamId,
_param: GenericParamDataRef<'_>,
- _infer_args: bool,
+ infer_args: bool,
_preceding_args: &[GenericArg<'db>],
+ had_count_error: bool,
) -> GenericArg<'db> {
// Always create an inference var, even when `infer_args == false`. This helps with diagnostics,
// and I think it's also required in the presence of `impl Trait` (that must be inferred).
- self.ctx.table.var_for_def(param_id, Span::Dummy)
+ let span =
+ if !infer_args || had_count_error { Span::Dummy } else { self.expr.into() };
+ self.ctx.table.var_for_def(param_id, span)
}
fn parent_arg(&mut self, param_idx: u32, _param_id: GenericParamId) -> GenericArg<'db> {
diff --git a/crates/hir-ty/src/next_solver.rs b/crates/hir-ty/src/next_solver.rs
index 78fdb1548c..47b4b1dc4a 100644
--- a/crates/hir-ty/src/next_solver.rs
+++ b/crates/hir-ty/src/next_solver.rs
@@ -93,6 +93,7 @@ pub struct DefaultTypes<'db> {
pub static_u8_slice: Ty<'db>,
/// `*mut ()`
pub mut_unit_ptr: Ty<'db>,
+ pub dyn_trait_dummy_self: Ty<'db>,
}
pub struct DefaultConsts<'db> {
@@ -272,6 +273,8 @@ pub fn default_types<'a, 'db>(db: &'db dyn HirDatabase) -> &'a DefaultAny<'db> {
u8_slice,
static_u8_slice,
mut_unit_ptr: create_ty(TyKind::RawPtr(unit, rustc_ast_ir::Mutability::Mut)),
+ // This type must not appear anywhere except here.
+ dyn_trait_dummy_self: create_ty(TyKind::Infer(rustc_type_ir::InferTy::FreshTy(0))),
},
consts: DefaultConsts {
error: create_const(ConstKind::Error(ErrorGuaranteed)),
diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs
index d51a4c1312..839bdf17e7 100644
--- a/crates/hir-ty/src/next_solver/infer/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/mod.rs
@@ -430,13 +430,12 @@ impl<'db> InferCtxt<'db> {
))
}
- pub(crate) fn insert_type_vars<T>(&self, ty: T, span: Span) -> T
+ pub(crate) fn insert_type_vars<T>(&self, ty: T) -> T
where
T: TypeFoldable<DbInterner<'db>>,
{
struct Folder<'a, 'db> {
infcx: &'a InferCtxt<'db>,
- span: Span,
}
impl<'db> TypeFolder<DbInterner<'db>> for Folder<'_, 'db> {
fn cx(&self) -> DbInterner<'db> {
@@ -449,7 +448,7 @@ impl<'db> InferCtxt<'db> {
}
if ty.is_ty_error() {
- self.infcx.next_ty_var(self.span)
+ self.infcx.next_ty_var(Span::Dummy)
} else {
ty.super_fold_with(self)
}
@@ -461,18 +460,18 @@ impl<'db> InferCtxt<'db> {
}
if ct.is_ct_error() {
- self.infcx.next_const_var(self.span)
+ self.infcx.next_const_var(Span::Dummy)
} else {
ct.super_fold_with(self)
}
}
fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
- if r.is_error() { self.infcx.next_region_var(self.span) } else { r }
+ if r.is_error() { self.infcx.next_region_var(Span::Dummy) } else { r }
}
}
- ty.fold_with(&mut Folder { infcx: self, span })
+ ty.fold_with(&mut Folder { infcx: self })
}
/// Evaluates whether the predicate can be satisfied in the given
diff --git a/crates/hir-ty/src/opaques.rs b/crates/hir-ty/src/opaques.rs
index d39e74b9af..4244b1bac4 100644
--- a/crates/hir-ty/src/opaques.rs
+++ b/crates/hir-ty/src/opaques.rs
@@ -10,7 +10,7 @@ use rustc_type_ir::inherent::Ty as _;
use syntax::ast;
use crate::{
- ImplTraitId, InferBodyId, InferenceResult, Span,
+ ImplTraitId, InferBodyId, InferenceResult,
db::{HirDatabase, InternedOpaqueTyId},
lower::{ImplTraitIdx, ImplTraits},
next_solver::{
@@ -146,7 +146,7 @@ pub(crate) fn tait_hidden_types(
}
// In the presence of errors, we attempt to create a unified type from all
// types. rustc doesn't do that, but this should improve the experience.
- let hidden_type = infcx.insert_type_vars(hidden_type.as_ref(), Span::Dummy);
+ let hidden_type = infcx.insert_type_vars(hidden_type.as_ref());
match result.entry(opaque_idx) {
la_arena::Entry::Vacant(entry) => {
entry.insert(StoredEarlyBinder::bind(hidden_type.store()));
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 76da816055..c0b8d93b47 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -2697,7 +2697,6 @@ fn generic_default_in_struct_literal() {
#[test]
fn generic_default_depending_on_other_type_arg() {
- // FIXME: the {unknown} is a bug
check_infer(
r#"
struct Thing<T = u128, F = fn() -> T> { t: T }
@@ -2714,7 +2713,7 @@ fn generic_default_depending_on_other_type_arg() {
83..130 '{ ...2 }; }': ()
89..91 't1': Thing<u32, fn() -> u32>
97..99 't2': Thing<u128, fn() -> u128>
- 105..127 'Thing:...1u32 }': Thing<u32, fn() -> {unknown}>
+ 105..127 'Thing:...1u32 }': Thing<u32, fn() -> u32>
121..125 '1u32': u32
"#]],
);
diff --git a/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs b/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
index 9c04d2be8a..5ee02279a2 100644
--- a/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
+++ b/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
@@ -43,8 +43,6 @@ struct Bar<T, U>(T, U);
fn foo() {
let _ = Bar::<()>;
// ^^^^^^ error: this struct takes 2 generic arguments but 1 generic argument was supplied
- // ^^^^^^^^^ error: type annotations needed
- // | full type: `fn Bar<(), {unknown}>((), {unknown}) -> Bar<(), {unknown}>`
}
"#,
@@ -53,10 +51,6 @@ fn foo() {
#[test]
fn enum_variant() {
- // FIXME: We should not have a "type annotations needed" error here, but to do that
- // we'll need to have access to the `InferenceContext` in `TyLoweringContext`, to
- // generate the infer var with a dummy span (instead of inserting it after the fact
- // with a non-dummy span).
check_diagnostics(
r#"
enum Enum<T, U> {
@@ -66,12 +60,8 @@ enum Enum<T, U> {
fn foo() {
let _ = Enum::<()>::Variant;
// ^^^^^^ error: this enum takes 2 generic arguments but 1 generic argument was supplied
- // ^^^^^^^^^^^^^^^^^^^ error: type annotations needed
- // | full type: `fn Variant<(), {unknown}>((), {unknown}) -> Enum<(), {unknown}>`
let _ = Enum::Variant::<()>;
// ^^^^^^ error: this enum takes 2 generic arguments but 1 generic argument was supplied
- // ^^^^^^^^^^^^^^^^^^^ error: type annotations needed
- // | full type: `fn Variant<(), {unknown}>((), {unknown}) -> Enum<(), {unknown}>`
}
"#,
@@ -137,8 +127,6 @@ struct Bar<T, const N: usize>(T);
fn bar() {
let _ = Bar::<()>;
// ^^^^^^ error: this struct takes 2 generic arguments but 1 generic argument was supplied
- // ^^^^^^^^^ error: type annotations needed
- // | full type: `fn Bar<(), _>(()) -> Bar<(), _>`
}
"#,
);