Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 140 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/diagnostics.rs | 6 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/path.rs | 30 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/unify.rs | 11 | ||||
| -rw-r--r-- | crates/hir-ty/src/lib.rs | 29 | ||||
| -rw-r--r-- | crates/hir-ty/src/lower.rs | 141 | ||||
| -rw-r--r-- | crates/hir-ty/src/lower/path.rs | 118 | ||||
| -rw-r--r-- | crates/hir-ty/src/method_resolution/confirm.rs | 7 | ||||
| -rw-r--r-- | crates/hir-ty/src/next_solver.rs | 3 | ||||
| -rw-r--r-- | crates/hir-ty/src/next_solver/infer/mod.rs | 11 | ||||
| -rw-r--r-- | crates/hir-ty/src/opaques.rs | 4 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/simple.rs | 3 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs | 12 |
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<(), _>` } "#, ); |