Unnamed repository; edit this file 'description' to name the repository.
-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<(), _>`
}
"#,
);