Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22168 from ChayimFriedman2/type-must-be-known-v2
feat: Feature a "type annotations needed" diagnostic when an infer var cannot be resolved at the end of inference
69 files changed, 1451 insertions, 782 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs index 497ed7d37f..51951896f2 100644 --- a/crates/hir-def/src/expr_store.rs +++ b/crates/hir-def/src/expr_store.rs @@ -561,6 +561,7 @@ impl ExpressionStore { | Pat::ConstBlock(..) | Pat::Wild | Pat::Missing + | Pat::Rest | Pat::Expr(_) => {} &Pat::Bind { subpat, .. } => { if let Some(subpat) = subpat { diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 3440fbee6d..fd8b50d714 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -2622,15 +2622,7 @@ impl<'db> ExprCollector<'db> { let expr_id = self.alloc_expr(expr, expr_ptr); Pat::Lit(expr_id) } - ast::Pat::RestPat(_) => { - // `RestPat` requires special handling and should not be mapped - // to a Pat. Here we are using `Pat::Missing` as a fallback for - // when `RestPat` is mapped to `Pat`, which can easily happen - // when the source code being analyzed has a malformed pattern - // which includes `..` in a place where it isn't valid. - - Pat::Missing - } + ast::Pat::RestPat(_) => Pat::Rest, ast::Pat::BoxPat(boxpat) => { let inner = self.collect_pat_opt(boxpat.pat(), binding_list); Pat::Box { inner } diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs index fdd0654508..bb35009f36 100644 --- a/crates/hir-def/src/expr_store/pretty.rs +++ b/crates/hir-def/src/expr_store/pretty.rs @@ -895,6 +895,7 @@ impl Printer<'_> { match pat { Pat::Missing => w!(self, "�"), + Pat::Rest => w!(self, ".."), Pat::Wild => w!(self, "_"), Pat::Tuple { args, ellipsis } => { w!(self, "("); diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs index a1a346cabc..93fa7ff961 100644 --- a/crates/hir-def/src/hir.rs +++ b/crates/hir-def/src/hir.rs @@ -666,6 +666,8 @@ pub struct RecordFieldPat { #[derive(Debug, Clone, Eq, PartialEq)] pub enum Pat { Missing, + /// A rest pattern. Not valid outside special context. + Rest, Wild, Tuple { args: Box<[PatId]>, @@ -721,6 +723,7 @@ impl Pat { | Pat::ConstBlock(..) | Pat::Wild | Pat::Missing + | Pat::Rest | Pat::Expr(_) => {} Pat::Bind { subpat, .. } => { subpat.iter().copied().for_each(f); diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs index abab3bfb25..2c2400a14a 100644 --- a/crates/hir-ty/src/autoderef.rs +++ b/crates/hir-ty/src/autoderef.rs @@ -10,7 +10,7 @@ use rustc_type_ir::inherent::{IntoKind, Ty as _}; use tracing::debug; use crate::{ - ParamEnvAndCrate, + ParamEnvAndCrate, Span, db::HirDatabase, infer::InferenceContext, next_solver::{ @@ -39,7 +39,7 @@ pub fn autoderef<'db>( ) -> impl Iterator<Item = Ty<'db>> + use<'db> { let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - let (ty, _) = infcx.instantiate_canonical(&ty); + let (ty, _) = infcx.instantiate_canonical(Span::Dummy, &ty); let autoderef = Autoderef::new(&infcx, env.param_env, ty); let mut v = Vec::new(); for (ty, _steps) in autoderef { diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 3bf2d9a6a6..99bad2682b 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -147,7 +147,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::const_param_ty_query)] #[salsa::transparent] - fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> Ty<'db>; + fn const_param_ty<'db>(&'db self, def: ConstParamId) -> Ty<'db>; #[salsa::invoke(crate::lower::impl_trait_with_diagnostics)] #[salsa::transparent] diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index ee33f7d158..4893d72a5c 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -258,7 +258,7 @@ impl<'db> UnsafeVisitor<'db> { self.on_unsafe_op(current.into(), UnsafetyReason::UnionField) } // `Or` only wraps other patterns, and `Missing`/`Wild` do not constitute a read. - Pat::Missing | Pat::Wild | Pat::Or(_) => {} + Pat::Missing | Pat::Rest | Pat::Wild | Pat::Or(_) => {} } } diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 8b0702c483..4aeb5ec71c 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -29,7 +29,7 @@ mod path; mod place_op; pub(crate) mod unify; -use std::{cell::OnceCell, convert::identity, fmt, iter, ops::Deref}; +use std::{cell::OnceCell, convert::identity, fmt, ops::Deref}; use base_db::{Crate, FxIndexMap}; use either::Either; @@ -50,11 +50,12 @@ use hir_def::{ use hir_expand::{mod_path::ModPath, name::Name}; use indexmap::IndexSet; use la_arena::ArenaMap; +use macros::{TypeFoldable, TypeVisitable}; use rustc_ast_ir::Mutability; use rustc_hash::{FxHashMap, FxHashSet}; use rustc_type_ir::{ AliasTyKind, TypeFoldable, - inherent::{AdtDef, IntoKind, Ty as _}, + inherent::{AdtDef, Const as _, IntoKind, Ty as _}, }; use smallvec::SmallVec; use span::Edition; @@ -62,7 +63,7 @@ use stdx::never; use thin_vec::ThinVec; use crate::{ - ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, TargetFeatures, + ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, Span, TargetFeatures, closure_analysis::PlaceBase, collect_type_inference_vars, db::{HirDatabase, InternedOpaqueTyId}, @@ -76,14 +77,15 @@ use crate::{ diagnostics::{Diagnostics, InferenceTyLoweringContext as TyLoweringContext}, expr::ExprIsRead, pat::PatOrigin, + unify::resolve_completely::WriteBackCtxt, }, lower::{ ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic, }, method_resolution::CandidateId, next_solver::{ - AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArgs, Region, StoredGenericArgs, - StoredTy, StoredTys, Ty, TyKind, Tys, + AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArgs, Region, StoredGenericArg, + StoredGenericArgs, StoredTy, StoredTys, Term, Ty, TyKind, Tys, abi::Safety, infer::{InferCtxt, ObligationInspector, traits::ObligationCause}, }, @@ -188,7 +190,7 @@ fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceRe // Array lengths are always `usize`. RootExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), // Const parameter default: look up the param's declared type. - RootExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty_ns( + RootExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty( ConstParamId::from_unchecked(TypeOrConstParamId { parent: def, local_id }), )), // Path const generic args: determining the expected type requires @@ -307,107 +309,152 @@ pub enum InferenceTyDiagnosticSource { Signature, } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, TypeVisitable, TypeFoldable)] pub enum InferenceDiagnostic { NoSuchField { + #[type_visitable(ignore)] field: ExprOrPatId, + #[type_visitable(ignore)] private: Option<LocalFieldId>, + #[type_visitable(ignore)] variant: VariantId, }, PrivateField { + #[type_visitable(ignore)] expr: ExprId, + #[type_visitable(ignore)] field: FieldId, }, PrivateAssocItem { + #[type_visitable(ignore)] id: ExprOrPatId, + #[type_visitable(ignore)] item: AssocItemId, }, UnresolvedField { + #[type_visitable(ignore)] expr: ExprId, receiver: StoredTy, + #[type_visitable(ignore)] name: Name, + #[type_visitable(ignore)] method_with_same_name_exists: bool, }, UnresolvedMethodCall { + #[type_visitable(ignore)] expr: ExprId, receiver: StoredTy, + #[type_visitable(ignore)] name: Name, /// Contains the type the field resolves to field_with_same_name: Option<StoredTy>, + #[type_visitable(ignore)] assoc_func_with_same_name: Option<FunctionId>, }, UnresolvedAssocItem { + #[type_visitable(ignore)] id: ExprOrPatId, }, UnresolvedIdent { + #[type_visitable(ignore)] id: ExprOrPatId, }, // FIXME: This should be emitted in body lowering BreakOutsideOfLoop { + #[type_visitable(ignore)] expr: ExprId, + #[type_visitable(ignore)] is_break: bool, + #[type_visitable(ignore)] bad_value_break: bool, }, MismatchedArgCount { + #[type_visitable(ignore)] call_expr: ExprId, + #[type_visitable(ignore)] expected: usize, + #[type_visitable(ignore)] found: usize, }, MismatchedTupleStructPatArgCount { + #[type_visitable(ignore)] pat: PatId, + #[type_visitable(ignore)] expected: usize, + #[type_visitable(ignore)] found: usize, }, ExpectedFunction { + #[type_visitable(ignore)] call_expr: ExprId, found: StoredTy, }, TypedHole { + #[type_visitable(ignore)] expr: ExprId, expected: StoredTy, }, CastToUnsized { + #[type_visitable(ignore)] expr: ExprId, cast_ty: StoredTy, }, InvalidCast { + #[type_visitable(ignore)] expr: ExprId, + #[type_visitable(ignore)] error: CastError, expr_ty: StoredTy, cast_ty: StoredTy, }, TyDiagnostic { + #[type_visitable(ignore)] source: InferenceTyDiagnosticSource, + #[type_visitable(ignore)] diag: TyLoweringDiagnostic, }, PathDiagnostic { + #[type_visitable(ignore)] node: ExprOrPatId, + #[type_visitable(ignore)] diag: PathLoweringDiagnostic, }, MethodCallIncorrectGenericsLen { + #[type_visitable(ignore)] expr: ExprId, + #[type_visitable(ignore)] provided_count: u32, + #[type_visitable(ignore)] expected_count: u32, + #[type_visitable(ignore)] kind: IncorrectGenericsLenKind, + #[type_visitable(ignore)] def: GenericDefId, }, MethodCallIncorrectGenericsOrder { + #[type_visitable(ignore)] expr: ExprId, + #[type_visitable(ignore)] param_id: GenericParamId, + #[type_visitable(ignore)] arg_idx: u32, /// Whether the `GenericArgs` contains a `Self` arg. + #[type_visitable(ignore)] has_self_arg: bool, }, InvalidLhsOfAssignment { + #[type_visitable(ignore)] lhs: ExprId, }, TypeMustBeKnown { - at_point: ExprOrPatId, + #[type_visitable(ignore)] + at_point: Span, + top_term: Option<StoredGenericArg>, }, } /// A mismatch between an expected and an inferred type. -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash, TypeVisitable, TypeFoldable)] pub struct TypeMismatch { pub expected: StoredTy, pub actual: StoredTy, @@ -1181,7 +1228,7 @@ pub(crate) struct InferenceContext<'body, 'db> { deferred_call_resolutions: FxHashMap<ExprId, Vec<DeferredCallResolution<'db>>>, diagnostics: Diagnostics, - vars_emitted_type_must_be_known_for: FxHashSet<Ty<'db>>, + vars_emitted_type_must_be_known_for: FxHashSet<Term<'db>>, } #[derive(Clone, Debug)] @@ -1331,14 +1378,15 @@ impl<'body, 'db> InferenceContext<'body, 'db> { // there is no problem in it being `pub(crate)`, remove this comment. fn resolve_all(self) -> InferenceResult { let InferenceContext { - mut table, + table, mut result, tuple_field_accesses_rev, diagnostics, types, + vars_emitted_type_must_be_known_for, .. } = self; - let mut diagnostics = diagnostics.finish(); + let diagnostics = diagnostics.finish(); // Destructure every single field so whenever new fields are added to `InferenceResult` we // don't forget to handle them here. let InferenceResult { @@ -1359,30 +1407,28 @@ impl<'body, 'db> InferenceContext<'body, 'db> { pat_adjustments, binding_modes: _, expr_adjustments, - tuple_field_access_types: _, + tuple_field_access_types, coercion_casts: _, - diagnostics: _, + diagnostics: result_diagnostics, } = &mut result; + let mut resolver = + WriteBackCtxt::new(table, diagnostics, vars_emitted_type_must_be_known_for); skipped_ref_pats.shrink_to_fit(); for ty in type_of_expr.values_mut() { - *ty = table.resolve_completely(ty.as_ref()).store(); - *has_errors = *has_errors || ty.as_ref().references_non_lt_error(); + resolver.resolve_completely(ty); } type_of_expr.shrink_to_fit(); for ty in type_of_pat.values_mut() { - *ty = table.resolve_completely(ty.as_ref()).store(); - *has_errors = *has_errors || ty.as_ref().references_non_lt_error(); + resolver.resolve_completely(ty); } type_of_pat.shrink_to_fit(); for ty in type_of_binding.values_mut() { - *ty = table.resolve_completely(ty.as_ref()).store(); - *has_errors = *has_errors || ty.as_ref().references_non_lt_error(); + resolver.resolve_completely(ty); } type_of_binding.shrink_to_fit(); for ty in type_of_type_placeholder.values_mut() { - *ty = table.resolve_completely(ty.as_ref()).store(); - *has_errors = *has_errors || ty.as_ref().references_non_lt_error(); + resolver.resolve_completely(ty); } type_of_type_placeholder.shrink_to_fit(); type_of_opaque.shrink_to_fit(); @@ -1390,61 +1436,25 @@ impl<'body, 'db> InferenceContext<'body, 'db> { if let Some(type_mismatches) = type_mismatches { *has_errors = true; for mismatch in type_mismatches.values_mut() { - mismatch.expected = table.resolve_completely(mismatch.expected.as_ref()).store(); - mismatch.actual = table.resolve_completely(mismatch.actual.as_ref()).store(); + resolver.resolve_type_mismatch(mismatch); } type_mismatches.shrink_to_fit(); } - diagnostics.retain_mut(|diagnostic| { - use InferenceDiagnostic::*; - match diagnostic { - ExpectedFunction { found: ty, .. } - | UnresolvedField { receiver: ty, .. } - | UnresolvedMethodCall { receiver: ty, .. } => { - *ty = table.resolve_completely(ty.as_ref()).store(); - // FIXME: Remove this when we are on par with rustc in terms of inference - if ty.as_ref().references_non_lt_error() { - return false; - } - - if let UnresolvedMethodCall { field_with_same_name, .. } = diagnostic - && let Some(ty) = field_with_same_name - { - *ty = table.resolve_completely(ty.as_ref()).store(); - if ty.as_ref().references_non_lt_error() { - *field_with_same_name = None; - } - } - } - TypedHole { expected: ty, .. } => { - *ty = table.resolve_completely(ty.as_ref()).store(); - } - _ => (), - } - true - }); - diagnostics.shrink_to_fit(); for (_, subst) in method_resolutions.values_mut() { - *subst = table.resolve_completely(subst.as_ref()).store(); - *has_errors = - *has_errors || subst.as_ref().types().any(|ty| ty.references_non_lt_error()); + resolver.resolve_completely(subst); } method_resolutions.shrink_to_fit(); for (_, subst) in assoc_resolutions.values_mut() { - *subst = table.resolve_completely(subst.as_ref()).store(); - *has_errors = - *has_errors || subst.as_ref().types().any(|ty| ty.references_non_lt_error()); + resolver.resolve_completely(subst); } assoc_resolutions.shrink_to_fit(); for adjustment in expr_adjustments.values_mut().flatten() { - adjustment.target = table.resolve_completely(adjustment.target.as_ref()).store(); - *has_errors = *has_errors || adjustment.target.as_ref().references_non_lt_error(); + resolver.resolve_completely(&mut adjustment.target); } expr_adjustments.shrink_to_fit(); for adjustments in pat_adjustments.values_mut() { for adjustment in &mut *adjustments { - adjustment.source = table.resolve_completely(adjustment.source.as_ref()).store(); - *has_errors = *has_errors || adjustment.source.as_ref().references_non_lt_error(); + resolver.resolve_completely(&mut adjustment.source); } adjustments.shrink_to_fit(); } @@ -1458,7 +1468,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { }; for (place, _, sources) in fake_reads { - *place = table.resolve_completely(std::mem::replace(place, dummy_place())); + resolver.resolve_completely_with_default(place, dummy_place()); place.projections.shrink_to_fit(); for source in &mut *sources { source.shrink_to_fit(); @@ -1469,7 +1479,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { for min_capture in min_captures.values_mut() { for captured in &mut *min_capture { let CapturedPlace { place, info, mutability: _ } = captured; - *place = table.resolve_completely(std::mem::replace(place, dummy_place())); + resolver.resolve_completely_with_default(place, dummy_place()); let CaptureInfo { sources, capture_kind: _ } = info; for source in &mut *sources { source.shrink_to_fit(); @@ -1481,17 +1491,18 @@ impl<'body, 'db> InferenceContext<'body, 'db> { min_captures.shrink_to_fit(); } closures_data.shrink_to_fit(); - result.tuple_field_access_types = tuple_field_accesses_rev + *tuple_field_access_types = tuple_field_accesses_rev .into_iter() - .map(|subst| table.resolve_completely(subst).store()) - .inspect(|subst| { - *has_errors = - *has_errors || subst.as_ref().iter().any(|ty| ty.references_non_lt_error()); + .map(|mut subst| { + resolver.resolve_completely(&mut subst); + subst.store() }) .collect(); - result.tuple_field_access_types.shrink_to_fit(); + tuple_field_access_types.shrink_to_fit(); - result.diagnostics = diagnostics; + let (diagnostics, resolver_has_errors) = resolver.resolve_diagnostics(); + *result_diagnostics = diagnostics; + *has_errors |= resolver_has_errors; result } @@ -1502,6 +1513,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { &data.store, InferenceTyDiagnosticSource::Signature, LifetimeElisionKind::for_const(self.interner(), id.loc(self.db).container), + Span::Dummy, ); self.return_ty = return_ty; @@ -1513,6 +1525,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { &data.store, InferenceTyDiagnosticSource::Signature, LifetimeElisionKind::Elided(self.types.regions.statik), + Span::Dummy, ); self.return_ty = return_ty; @@ -1537,7 +1550,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { GenericArgs::for_item_with_defaults( self.interner(), va_list.into(), - |_, id, _| self.table.next_var_for_param(id), + |_, id, _| self.table.var_for_def(id, Span::Dummy), ), ), None => self.err_ty(), @@ -1545,15 +1558,16 @@ impl<'body, 'db> InferenceContext<'body, 'db> { param_tys.push(va_list_ty); } - let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.next_ty_var())); + let mut param_tys = param_tys.into_iter(); if let Some(self_param) = self_param && let Some(ty) = param_tys.next() { - let ty = self.process_user_written_ty(ty); + let ty = self.process_user_written_ty(Span::Dummy, ty); self.write_binding_ty(self_param, ty); } - for (ty, pat) in param_tys.zip(params) { - let ty = self.process_user_written_ty(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); self.infer_top_pat(*pat, ty, PatOrigin::Param); } @@ -1568,7 +1582,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { ctx.lower_ty(return_ty) }, ); - self.process_user_written_ty(return_ty) + self.process_user_written_ty(Span::Dummy, return_ty) } None => self.types.types.unit, }; @@ -1602,10 +1616,10 @@ impl<'body, 'db> InferenceContext<'body, 'db> { /// but if we return a new var, mark it so that no diagnostics will be issued on it. fn insert_type_vars_shallow(&mut self, ty: Ty<'db>) -> Ty<'db> { if ty.is_ty_error() { - let var = self.table.next_ty_var(); + let var = self.table.next_ty_var(Span::Dummy); // Suppress future errors on this var. Add more things here when we add more diagnostics. - self.vars_emitted_type_must_be_known_for.insert(var); + self.vars_emitted_type_must_be_known_for.insert(var.into()); var } else { @@ -1613,6 +1627,10 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } } + pub(super) fn insert_const_vars_shallow(&mut self, c: Const<'db>) -> Const<'db> { + if c.is_ct_error() { self.table.next_const_var(Span::Dummy) } else { c } + } + fn infer_body(&mut self, body_expr: ExprId) { match self.return_coercion { Some(_) => self.infer_return(body_expr), @@ -1746,10 +1764,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> { store: &ExpressionStore, type_source: InferenceTyDiagnosticSource, lifetime_elision: LifetimeElisionKind<'db>, + span: Span, ) -> Ty<'db> { let ty = self .with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref)); - let ty = self.process_user_written_ty(ty); + 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. @@ -1776,6 +1795,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, + type_ref.into(), ) } @@ -1786,17 +1806,22 @@ impl<'body, 'db> InferenceContext<'body, 'db> { LifetimeElisionKind::Infer, |ctx| ctx.lower_const(const_ref, ty), ); - self.insert_type_vars(const_) + self.insert_type_vars(const_, const_ref.expr.into()) } - pub(crate) fn make_path_as_body_const(&mut self, path: &Path, ty: Ty<'db>) -> Const<'db> { + pub(crate) fn make_path_as_body_const( + &mut self, + type_ref: TypeRefId, + path: &Path, + ty: Ty<'db>, + ) -> Const<'db> { let const_ = self.with_ty_lowering( self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, |ctx| ctx.lower_path_as_const(path, ty), ); - self.insert_type_vars(const_) + self.insert_type_vars(const_, type_ref.into()) } fn err_ty(&self) -> Ty<'db> { @@ -1810,14 +1835,14 @@ impl<'body, 'db> InferenceContext<'body, 'db> { LifetimeElisionKind::Infer, |ctx| ctx.lower_lifetime(lifetime_ref), ); - self.insert_type_vars(lt) + self.insert_type_vars(lt, Span::Dummy) } - fn insert_type_vars<T>(&mut self, ty: T) -> T + fn insert_type_vars<T>(&mut self, ty: T, span: Span) -> T where T: TypeFoldable<DbInterner<'db>>, { - self.table.insert_type_vars(ty) + self.table.insert_type_vars(ty, span) } /// Attempts to returns the deeply last field of nested structures, but @@ -1882,8 +1907,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, ty: Ty<'db>) -> Ty<'db> { - self.table.process_user_written_ty(ty) + fn process_user_written_ty(&mut self, span: Span, ty: Ty<'db>) -> Ty<'db> { + self.table.process_user_written_ty(span, ty) } /// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation, @@ -1974,8 +1999,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> { node: ExprOrPatId, ty: Ty<'db>, ) -> Ty<'db> { - if self.vars_emitted_type_must_be_known_for.insert(ty) { - self.push_diagnostic(InferenceDiagnostic::TypeMustBeKnown { at_point: node }); + if self.vars_emitted_type_must_be_known_for.insert(ty.into()) { + self.push_diagnostic(InferenceDiagnostic::TypeMustBeKnown { + at_point: node.into(), + top_term: None, + }); } self.types.types.error } @@ -2024,7 +2052,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { return (self.err_ty(), None); } let (mut ty, type_ns) = ctx.lower_ty_ext(type_anchor); - ty = self.table.process_user_written_ty(ty); + ty = self.table.process_user_written_ty(type_anchor.into(), ty); if let Some(TypeNs::SelfType(impl_)) = type_ns && let Some(trait_ref) = self.db.impl_trait(impl_) @@ -2036,7 +2064,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> { .associated_type_by_name(segments.first().unwrap().name) { // `<Self>::AssocType` - let args = self.infcx().fill_rest_fresh_args(assoc_type.into(), trait_ref.args); + let args = self.infcx().fill_rest_fresh_args( + node.into(), + assoc_type.into(), + trait_ref.args, + ); let alias = Ty::new_alias( self.interner(), AliasTy::new_from_args( @@ -2090,14 +2122,14 @@ impl<'body, 'db> InferenceContext<'body, 'db> { .db .ty(var.lookup(self.db).parent.into()) .instantiate(interner, args); - let ty = self.insert_type_vars(ty); + let ty = self.insert_type_vars(ty, Span::Dummy); return (ty, Some(var.into())); } ValueNs::StructId(strukt) => { let args = path_ctx.substs_from_path(strukt.into(), true, false); drop(ctx); let ty = self.db.ty(strukt.into()).instantiate(interner, args); - let ty = self.insert_type_vars(ty); + let ty = self.insert_type_vars(ty, Span::Dummy); return (ty, Some(strukt.into())); } ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None), @@ -2119,21 +2151,21 @@ impl<'body, 'db> InferenceContext<'body, 'db> { let args = path_ctx.substs_from_path(strukt.into(), true, false); drop(ctx); let ty = self.db.ty(strukt.into()).instantiate(interner, args); - let ty = self.insert_type_vars(ty); + let ty = self.insert_type_vars(ty, Span::Dummy); 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); drop(ctx); let ty = self.db.ty(u.into()).instantiate(interner, args); - let ty = self.insert_type_vars(ty); + let ty = self.insert_type_vars(ty, Span::Dummy); forbid_unresolved_segments(self, (ty, Some(u.into())), unresolved) } TypeNs::EnumVariantId(var) => { let args = path_ctx.substs_from_path(var.into(), true, false); drop(ctx); let ty = self.db.ty(var.lookup(self.db).parent.into()).instantiate(interner, args); - let ty = self.insert_type_vars(ty); + let ty = self.insert_type_vars(ty, Span::Dummy); forbid_unresolved_segments(self, (ty, Some(var.into())), unresolved) } TypeNs::SelfType(impl_id) => { @@ -2188,7 +2220,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { (ty, _) = path_ctx.lower_partly_resolved_path(resolution, true); tried_resolving_once = true; - ty = self.table.process_user_written_ty(ty); + ty = self.table.process_user_written_ty(node.into(), ty); if ty.is_ty_error() { return (self.err_ty(), None); } @@ -2219,7 +2251,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } let (mut ty, _) = path_ctx.lower_partly_resolved_path(resolution, true); - ty = self.table.process_user_written_ty(ty); + ty = self.table.process_user_written_ty(node.into(), ty); if let Some(segment) = remaining_segments.get(1) && let Some((AdtId::EnumId(id), _)) = ty.as_adt() @@ -2256,7 +2288,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { drop(ctx); let interner = DbInterner::conjure(); let ty = self.db.ty(it.into()).instantiate(interner, args); - let ty = self.insert_type_vars(ty); + let ty = self.insert_type_vars(ty, Span::Dummy); self.resolve_variant_on_alias(ty, unresolved, mod_path) } @@ -2487,8 +2519,8 @@ impl<'db> Expectation<'db> { } } - fn coercion_target_type(&self, table: &mut unify::InferenceTable<'db>) -> Ty<'db> { - self.only_has_type(table).unwrap_or_else(|| table.next_ty_var()) + fn coercion_target_type(&self, table: &mut unify::InferenceTable<'db>, span: Span) -> Ty<'db> { + self.only_has_type(table).unwrap_or_else(|| table.next_ty_var(span)) } /// Comment copied from rustc: diff --git a/crates/hir-ty/src/infer/callee.rs b/crates/hir-ty/src/infer/callee.rs index a470c92124..ffdde58c48 100644 --- a/crates/hir-ty/src/infer/callee.rs +++ b/crates/hir-ty/src/infer/callee.rs @@ -5,7 +5,9 @@ use std::iter; use intern::sym; use tracing::debug; -use hir_def::{CallableDefId, hir::ExprId, signatures::FunctionSignature}; +use hir_def::{ + CallableDefId, ConstParamId, TypeOrConstParamId, hir::ExprId, signatures::FunctionSignature, +}; use rustc_type_ir::{ InferTy, Interner, inherent::{GenericArgs as _, IntoKind, Ty as _}, @@ -20,7 +22,7 @@ use crate::{ }, method_resolution::{MethodCallee, TreatNotYetDefinedOpaques}, next_solver::{ - FnSig, Ty, TyKind, + ConstKind, FnSig, Ty, TyKind, infer::{BoundRegionConversionTime, traits::ObligationCause}, }, }; @@ -82,7 +84,7 @@ impl<'db> InferenceContext<'_, 'db> { } Some(CallStep::Builtin(callee_ty)) => { - self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected) + self.confirm_builtin_call(callee_expr, call_expr, callee_ty, arg_exprs, expected) } Some(CallStep::DeferredClosure(_def_id, fn_sig)) => { @@ -128,6 +130,7 @@ impl<'db> InferenceContext<'_, 'db> { { let closure_sig = args.as_closure().sig(); let closure_sig = autoderef.ctx().infcx().instantiate_binder_with_fresh_vars( + callee_expr.into(), BoundRegionConversionTime::FnCall, closure_sig, ); @@ -158,15 +161,16 @@ impl<'db> InferenceContext<'_, 'db> { let closure_args = args.as_coroutine_closure(); let coroutine_closure_sig = autoderef.ctx().infcx().instantiate_binder_with_fresh_vars( + callee_expr.into(), BoundRegionConversionTime::FnCall, closure_args.coroutine_closure_sig(), ); - let tupled_upvars_ty = autoderef.ctx().table.next_ty_var(); + let tupled_upvars_ty = autoderef.ctx().table.next_ty_var(call_expr.into()); // We may actually receive a coroutine back whose kind is different // from the closure that this dispatched from. This is because when // we have no captures, we automatically implement `FnOnce`. This // impl forces the closure kind to `FnOnce` i.e. `u8`. - let kind_ty = autoderef.ctx().table.next_ty_var(); + let kind_ty = autoderef.ctx().table.next_ty_var(call_expr.into()); let interner = autoderef.ctx().interner(); let call_sig = interner.mk_fn_sig( [coroutine_closure_sig.tupled_inputs_ty], @@ -297,7 +301,7 @@ impl<'db> InferenceContext<'_, 'db> { let opt_input_type = opt_arg_exprs.map(|arg_exprs| { Ty::new_tup_from_iter( self.interner(), - arg_exprs.iter().map(|_| self.table.next_ty_var()), + arg_exprs.iter().map(|&arg| self.table.next_ty_var(arg.into())), ) }); @@ -347,12 +351,26 @@ impl<'db> InferenceContext<'_, 'db> { fn check_legacy_const_generics( &mut self, callee: Option<CallableDefId>, + callee_ty: Ty<'db>, args: &[ExprId], ) -> Box<[u32]> { - let func = match callee { - Some(CallableDefId::FunctionId(func)) => func, + let (func, fn_generic_args) = match (callee, callee_ty.kind()) { + (Some(CallableDefId::FunctionId(func)), TyKind::FnDef(_, fn_generic_args)) => { + (func, fn_generic_args) + } _ => return Default::default(), }; + let generics = crate::generics::generics(self.db, func.into()); + let const_params = generics + .iter_self_type_or_consts() + .filter(|(_, param_data)| param_data.const_param().is_some()) + .map(|(idx, _)| { + ConstParamId::from_unchecked(TypeOrConstParamId { + parent: func.into(), + local_id: idx, + }) + }) + .collect::<Vec<_>>(); let data = FunctionSignature::of(self.db, func); let Some(legacy_const_generics_indices) = data.legacy_const_generics_indices(self.db, func) @@ -374,11 +392,29 @@ impl<'db> InferenceContext<'_, 'db> { } // check legacy const parameters - for arg_idx in legacy_const_generics_indices.iter().copied() { + for (const_idx, arg_idx) in legacy_const_generics_indices.iter().copied().enumerate() { if arg_idx >= args.len() as u32 { continue; } - let expected = Expectation::none(); // FIXME use actual const ty, when that is lowered correctly + + if let Some(const_arg) = fn_generic_args.get(const_idx).and_then(|it| it.konst()) + && let ConstKind::Infer(_) = const_arg.kind() + { + // Instantiate the generic arg with an error type, to prevent errors from it. + // FIXME: Actually lower the expression as const. + _ = self + .table + .at(&ObligationCause::dummy()) + .eq(self.types.consts.error, const_arg) + .map(|infer_ok| self.table.register_infer_ok(infer_ok)); + } + + let expected = if let Some(&const_param) = const_params.get(const_idx) { + Expectation::has_type(self.db.const_param_ty(const_param)) + } else { + Expectation::None + }; + self.infer_expr(args[arg_idx as usize], &expected, ExprIsRead::Yes); // FIXME: evaluate and unify with the const } @@ -388,6 +424,7 @@ impl<'db> InferenceContext<'_, 'db> { fn confirm_builtin_call( &mut self, + callee_expr: ExprId, call_expr: ExprId, callee_ty: Ty<'db>, arg_exprs: &[ExprId], @@ -411,11 +448,13 @@ impl<'db> InferenceContext<'_, 'db> { // renormalize the associated types at this point, since they // previously appeared within a `Binder<>` and hence would not // have been normalized before. - let fn_sig = self - .infcx() - .instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, fn_sig); + let fn_sig = self.infcx().instantiate_binder_with_fresh_vars( + callee_expr.into(), + BoundRegionConversionTime::FnCall, + fn_sig, + ); - let indices_to_skip = self.check_legacy_const_generics(def_id, arg_exprs); + let indices_to_skip = self.check_legacy_const_generics(def_id, callee_ty, arg_exprs); self.check_call_arguments( call_expr, fn_sig.inputs(), diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index a53ab7daaa..93c98f2542 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -65,19 +65,19 @@ impl<'db> InferenceContext<'_, 'db> { let (expected_sig, expected_kind) = match expected.to_option(&mut self.table) { Some(ty) => { let ty = self.table.try_structurally_resolve_type(ty); - self.deduce_closure_signature(ty, closure_kind) + self.deduce_closure_signature(closure_expr, ty, closure_kind) } None => (None, None), }; let ClosureSignatures { bound_sig, mut liberated_sig } = - self.sig_of_closure(arg_types, ret_type, expected_sig); + self.sig_of_closure(closure_expr, arg_types, ret_type, expected_sig); debug!(?bound_sig, ?liberated_sig); let parent_args = GenericArgs::identity_for_item(interner, self.generic_def.into()); - let tupled_upvars_ty = self.table.next_ty_var(); + let tupled_upvars_ty = self.table.next_ty_var(closure_expr.into()); // FIXME: We could probably actually just unify this further -- // instead of having a `FnSig` and a `Option<CoroutineTypes>`, @@ -103,7 +103,7 @@ impl<'db> InferenceContext<'_, 'db> { Some(kind) => Ty::from_closure_kind(interner, kind), // Create a type variable (for now) to represent the closure kind. // It will be unified during the upvar inference phase (`upvar.rs`) - None => self.table.next_ty_var(), + None => self.table.next_ty_var(closure_expr.into()), }; let closure_args = ClosureArgs::new( @@ -123,7 +123,7 @@ impl<'db> InferenceContext<'_, 'db> { } ClosureKind::Coroutine(_) | ClosureKind::AsyncBlock { .. } => { let yield_ty = match closure_kind { - ClosureKind::Coroutine(_) => self.table.next_ty_var(), + ClosureKind::Coroutine(_) => self.table.next_ty_var(closure_expr.into()), ClosureKind::AsyncBlock { .. } => self.types.types.unit, _ => unreachable!(), }; @@ -138,7 +138,7 @@ impl<'db> InferenceContext<'_, 'db> { // ty of `().` let kind_ty = match closure_kind { ClosureKind::AsyncBlock { source: CoroutineSource::Closure } => { - self.table.next_ty_var() + self.table.next_ty_var(closure_expr.into()) } _ => self.types.types.unit, }; @@ -169,17 +169,17 @@ impl<'db> InferenceContext<'_, 'db> { let (bound_return_ty, bound_yield_ty) = (bound_sig.skip_binder().output(), self.types.types.unit); // Compute all of the variables that will be used to populate the coroutine. - let resume_ty = self.table.next_ty_var(); + let resume_ty = self.table.next_ty_var(closure_expr.into()); let closure_kind_ty = match expected_kind { Some(kind) => Ty::from_closure_kind(interner, kind), // Create a type variable (for now) to represent the closure kind. // It will be unified during the upvar inference phase (`upvar.rs`) - None => self.table.next_ty_var(), + None => self.table.next_ty_var(closure_expr.into()), }; - let coroutine_captures_by_ref_ty = self.table.next_ty_var(); + let coroutine_captures_by_ref_ty = self.table.next_ty_var(closure_expr.into()); let closure_args = CoroutineClosureArgs::new( interner, @@ -214,10 +214,10 @@ impl<'db> InferenceContext<'_, 'db> { // Create a type variable (for now) to represent the closure kind. // It will be unified during the upvar inference phase (`upvar.rs`) - None => self.table.next_ty_var(), + None => self.table.next_ty_var(closure_expr.into()), }; - let coroutine_upvars_ty = self.table.next_ty_var(); + let coroutine_upvars_ty = self.table.next_ty_var(closure_expr.into()); let coroutine_closure_id = InternedCoroutineClosureId::new( self.db, @@ -316,12 +316,14 @@ impl<'db> InferenceContext<'_, 'db> { /// are about to type check: fn deduce_closure_signature( &mut self, + closure_expr: ExprId, expected_ty: Ty<'db>, closure_kind: ClosureKind, ) -> (Option<PolyFnSig<'db>>, Option<rustc_type_ir::ClosureKind>) { match expected_ty.kind() { TyKind::Alias(AliasTy { kind: rustc_type_ir::Opaque { def_id }, args, .. }) => self .deduce_closure_signature_from_predicates( + closure_expr, expected_ty, closure_kind, def_id @@ -333,7 +335,7 @@ impl<'db> InferenceContext<'_, 'db> { TyKind::Dynamic(object_type, ..) => { let sig = object_type.projection_bounds().into_iter().find_map(|pb| { let pb = pb.with_self_ty(self.interner(), Ty::new_unit(self.interner())); - self.deduce_sig_from_projection(closure_kind, pb) + self.deduce_sig_from_projection(closure_expr, closure_kind, pb) }); let kind = object_type .principal_def_id() @@ -342,6 +344,7 @@ impl<'db> InferenceContext<'_, 'db> { } TyKind::Infer(rustc_type_ir::TyVar(vid)) => self .deduce_closure_signature_from_predicates( + closure_expr, Ty::new_var(self.interner(), self.table.infer_ctxt.root_var(vid)), closure_kind, self.table.obligations_for_self_ty(vid).into_iter().map(|obl| obl.predicate), @@ -361,6 +364,7 @@ impl<'db> InferenceContext<'_, 'db> { fn deduce_closure_signature_from_predicates( &mut self, + closure_expr: ExprId, expected_ty: Ty<'db>, closure_kind: ClosureKind, predicates: impl DoubleEndedIterator<Item = Predicate<'db>>, @@ -388,6 +392,7 @@ impl<'db> InferenceContext<'_, 'db> { bound_predicate.skip_binder() { let inferred_sig = self.deduce_sig_from_projection( + closure_expr, closure_kind, bound_predicate.rebind(proj_predicate), ); @@ -430,7 +435,7 @@ impl<'db> InferenceContext<'_, 'db> { // This is a bit weird and means we may wind up discarding the goal due to it naming `expected_ty` // even though the normalized form may not name `expected_ty`. However, this matches the existing // behaviour of the old solver and would be technically a breaking change to fix. - let generalized_fnptr_sig = self.table.next_ty_var(); + let generalized_fnptr_sig = self.table.next_ty_var(closure_expr.into()); let inferred_fnptr_sig = Ty::new_fn_ptr(self.interner(), inferred_sig); // FIXME: Report diagnostics. _ = self @@ -500,6 +505,7 @@ impl<'db> InferenceContext<'_, 'db> { /// know that. fn deduce_sig_from_projection( &mut self, + closure_expr: ExprId, closure_kind: ClosureKind, projection: PolyProjectionPredicate<'db>, ) -> Option<PolyFnSig<'db>> { @@ -518,7 +524,7 @@ impl<'db> InferenceContext<'_, 'db> { // `F: FnOnce() -> Fut, Fut: Future<Output = T>` style bound. Let's still // guide inference here, since it's beneficial for the user. ClosureKind::AsyncClosure if Some(def_id) == self.lang_items.FnOnceOutput => { - self.extract_sig_from_projection_and_future_bound(projection) + self.extract_sig_from_projection_and_future_bound(closure_expr, projection) } _ => None, } @@ -573,6 +579,7 @@ impl<'db> InferenceContext<'_, 'db> { /// projection, and the output will be an unconstrained type variable instead. fn extract_sig_from_projection_and_future_bound( &mut self, + closure_expr: ExprId, projection: PolyProjectionPredicate<'db>, ) -> Option<PolyFnSig<'db>> { let projection = self.resolve_vars_if_possible(projection); @@ -624,7 +631,7 @@ impl<'db> InferenceContext<'_, 'db> { // // FIXME: We probably should store this signature inference output in a way // that does not misuse a `FnSig` type, but that can be done separately. - let return_ty = return_ty.unwrap_or_else(|| self.table.next_ty_var()); + let return_ty = return_ty.unwrap_or_else(|| self.table.next_ty_var(closure_expr.into())); let sig = projection.rebind(self.interner().mk_fn_sig_safe_rust_abi(input_tys, return_ty)); @@ -633,14 +640,15 @@ impl<'db> InferenceContext<'_, 'db> { fn sig_of_closure( &mut self, + closure_expr: ExprId, decl_inputs: &[Option<TypeRefId>], decl_output: Option<TypeRefId>, expected_sig: Option<PolyFnSig<'db>>, ) -> ClosureSignatures<'db> { if let Some(e) = expected_sig { - self.sig_of_closure_with_expectation(decl_inputs, decl_output, e) + self.sig_of_closure_with_expectation(closure_expr, decl_inputs, decl_output, e) } else { - self.sig_of_closure_no_expectation(decl_inputs, decl_output) + self.sig_of_closure_no_expectation(closure_expr, decl_inputs, decl_output) } } @@ -648,10 +656,11 @@ impl<'db> InferenceContext<'_, 'db> { /// types that the user gave into a signature. fn sig_of_closure_no_expectation( &mut self, + closure_expr: ExprId, decl_inputs: &[Option<TypeRefId>], decl_output: Option<TypeRefId>, ) -> ClosureSignatures<'db> { - let bound_sig = self.supplied_sig_of_closure(decl_inputs, decl_output); + let bound_sig = self.supplied_sig_of_closure(closure_expr, decl_inputs, decl_output); self.closure_sigs(bound_sig) } @@ -705,6 +714,7 @@ impl<'db> InferenceContext<'_, 'db> { /// regions with depth 1, which are bound then by the closure. fn sig_of_closure_with_expectation( &mut self, + closure_expr: ExprId, decl_inputs: &[Option<TypeRefId>], decl_output: Option<TypeRefId>, expected_sig: PolyFnSig<'db>, @@ -713,7 +723,7 @@ impl<'db> InferenceContext<'_, 'db> { // expectation if things don't see to match up with what we // expect. if expected_sig.c_variadic() { - return self.sig_of_closure_no_expectation(decl_inputs, decl_output); + return self.sig_of_closure_no_expectation(closure_expr, decl_inputs, decl_output); } else if expected_sig.skip_binder().inputs_and_output.len() != decl_inputs.len() + 1 { return self .sig_of_closure_with_mismatched_number_of_arguments(decl_inputs, decl_output); @@ -745,9 +755,14 @@ impl<'db> InferenceContext<'_, 'db> { // Along the way, it also writes out entries for types that the user // wrote into our typeck results, which are then later used by the privacy // check. - match self.merge_supplied_sig_with_expectation(decl_inputs, decl_output, closure_sigs) { + match self.merge_supplied_sig_with_expectation( + closure_expr, + decl_inputs, + decl_output, + closure_sigs, + ) { Ok(infer_ok) => self.table.register_infer_ok(infer_ok), - Err(_) => self.sig_of_closure_no_expectation(decl_inputs, decl_output), + Err(_) => self.sig_of_closure_no_expectation(closure_expr, decl_inputs, decl_output), } } @@ -766,6 +781,7 @@ impl<'db> InferenceContext<'_, 'db> { /// strategy. fn merge_supplied_sig_with_expectation( &mut self, + closure_expr: ExprId, decl_inputs: &[Option<TypeRefId>], decl_output: Option<TypeRefId>, mut expected_sigs: ClosureSignatures<'db>, @@ -774,7 +790,7 @@ impl<'db> InferenceContext<'_, 'db> { // // (See comment on `sig_of_closure_with_expectation` for the // meaning of these letters.) - let supplied_sig = self.supplied_sig_of_closure(decl_inputs, decl_output); + let supplied_sig = self.supplied_sig_of_closure(closure_expr, decl_inputs, decl_output); debug!(?supplied_sig); @@ -795,6 +811,7 @@ impl<'db> InferenceContext<'_, 'db> { self.table.commit_if_ok(|table| { let mut all_obligations = PredicateObligations::new(); let supplied_sig = table.infer_ctxt.instantiate_binder_with_fresh_vars( + closure_expr.into(), BoundRegionConversionTime::FnCall, supplied_sig, ); @@ -842,25 +859,20 @@ impl<'db> InferenceContext<'_, 'db> { /// Also, record this closure signature for later. fn supplied_sig_of_closure( &mut self, + closure_expr: ExprId, decl_inputs: &[Option<TypeRefId>], decl_output: Option<TypeRefId>, ) -> PolyFnSig<'db> { let interner = self.interner(); let supplied_return = match decl_output { - Some(output) => { - let output = self.make_body_ty(output); - self.process_user_written_ty(output) - } - None => self.table.next_ty_var(), + Some(output) => self.make_body_ty(output), + None => self.table.next_ty_var(closure_expr.into()), }; // First, convert the types that the user supplied (if any). let supplied_arguments = decl_inputs.iter().map(|&input| match input { - Some(input) => { - let input = self.make_body_ty(input); - self.process_user_written_ty(input) - } - None => self.table.next_ty_var(), + Some(input) => self.make_body_ty(input), + None => self.table.next_ty_var(closure_expr.into()), }); Binder::dummy(interner.mk_fn_sig( diff --git a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index f140b12491..0fd3cda31d 100644 --- a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -1026,7 +1026,8 @@ impl<'a, 'b, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'b, 'db, D> { | Pat::Ref { .. } | Pat::Tuple { .. } | Pat::Wild - | Pat::Missing => { + | Pat::Missing + | Pat::Rest => { // If the PatKind is Or, Box, Ref, Guard, or Tuple, the relevant accesses // are made later as these patterns contains subpatterns. // If the PatKind is Missing, Wild or Err, any relevant accesses are made when processing @@ -1671,6 +1672,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { | Pat::ConstBlock(..) | Pat::Range { .. } | Pat::Missing + | Pat::Rest | Pat::Wild => { // always ok } diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs index 962fc752a5..55e02a6933 100644 --- a/crates/hir-ty/src/infer/coerce.rs +++ b/crates/hir-ty/src/infer/coerce.rs @@ -52,7 +52,7 @@ use smallvec::SmallVec; use tracing::{debug, instrument}; use crate::{ - Adjust, Adjustment, AutoBorrow, ParamEnvAndCrate, PointerCast, TargetFeatures, + Adjust, Adjustment, AutoBorrow, ParamEnvAndCrate, PointerCast, Span, TargetFeatures, autoderef::Autoderef, db::{HirDatabase, InternedClosure, InternedClosureId}, infer::{ @@ -316,7 +316,8 @@ where if b.is_infer() { // Two unresolved type variables: create a `Coerce` predicate. - let target_ty = if self.use_lub { self.infcx().next_ty_var() } else { b }; + let target_ty = + if self.use_lub { self.infcx().next_ty_var(self.cause.span()) } else { b }; let mut obligations = PredicateObligations::with_capacity(2); for &source_ty in &[a, b] { @@ -463,7 +464,7 @@ where } else { if r_borrow_var.is_none() { // create var lazily, at most once - let r = self.infcx().next_region_var(); + let r = self.infcx().next_region_var(self.cause.span()); r_borrow_var = Some(r); // [4] above } r_borrow_var.unwrap() @@ -624,7 +625,7 @@ where (TyKind::Ref(_, ty_a, mutbl_a), TyKind::Ref(_, _, mutbl_b)) => { coerce_mutbls(mutbl_a, mutbl_b)?; - let r_borrow = self.infcx().next_region_var(); + let r_borrow = self.infcx().next_region_var(self.cause.span()); // We don't allow two-phase borrows here, at least for initial // implementation. If it happens that this coercion is a function argument, @@ -658,7 +659,7 @@ where // the `CoerceUnsized` target type and the expected type. // We only have the latter, so we use an inference variable // for the former and let type inference do the rest. - let coerce_target = self.infcx().next_ty_var(); + let coerce_target = self.infcx().next_ty_var(self.cause.span()); let mut coercion = self.unify_and( coerce_target, @@ -688,6 +689,7 @@ where errored: false, unsize_did, coerce_unsized_did, + span: self.cause.span(), }, ) .is_break() @@ -899,7 +901,7 @@ impl<'db> InferenceContext<'_, 'db> { target = self.table.try_structurally_resolve_type(target); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); - let cause = ObligationCause::new(); + let cause = ObligationCause::with_span(expr.into()); let coerce_never = self.expr_guaranteed_to_constitute_read_for_never(expr, expr_is_read); let mut coerce = Coerce { delegate: InferenceCoercionDelegate(self), @@ -974,8 +976,12 @@ impl<'db> InferenceContext<'_, 'db> { match self.table.commit_if_ok(|table| { // We need to eagerly handle nested obligations due to lazy norm. let mut ocx = ObligationCtxt::new(&table.infer_ctxt); - let value = - ocx.lub(&ObligationCause::new(), table.param_env, prev_ty, new_ty)?; + let value = ocx.lub( + &ObligationCause::with_span(new.into()), + table.param_env, + prev_ty, + new_ty, + )?; if ocx.try_evaluate_obligations().is_empty() { Ok(InferOk { value, obligations: ocx.into_pending_obligations() }) } else { @@ -1023,7 +1029,7 @@ impl<'db> InferenceContext<'_, 'db> { let sig = self .table .infer_ctxt - .at(&ObligationCause::new(), self.table.param_env) + .at(&ObligationCause::with_span(new.into()), self.table.param_env) .lub(a_sig, b_sig) .map(|ok| self.table.register_infer_ok(ok))?; @@ -1069,7 +1075,7 @@ impl<'db> InferenceContext<'_, 'db> { // operate on values and not places, so a never coercion is valid. let mut coerce = Coerce { delegate: InferenceCoercionDelegate(self), - cause: ObligationCause::new(), + cause: ObligationCause::with_span(new.into()), allow_two_phase: AllowTwoPhase::No, coerce_never: true, use_lub: true, @@ -1105,7 +1111,7 @@ impl<'db> InferenceContext<'_, 'db> { .commit_if_ok(|table| { table .infer_ctxt - .at(&ObligationCause::new(), table.param_env) + .at(&ObligationCause::with_span(new.into()), table.param_env) .lub(prev_ty, new_ty) }) .unwrap_err()) @@ -1451,7 +1457,7 @@ fn coerce<'db>( ) -> Result<(Vec<Adjustment>, Ty<'db>), TypeError<DbInterner<'db>>> { let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - let ((ty1_with_vars, ty2_with_vars), vars) = infcx.instantiate_canonical(tys); + let ((ty1_with_vars, ty2_with_vars), vars) = infcx.instantiate_canonical(Span::Dummy, tys); let cause = ObligationCause::new(); // FIXME: Target features. @@ -1611,11 +1617,16 @@ struct CoerceVisitor<'a, D> { errored: bool, unsize_did: TraitId, coerce_unsized_did: TraitId, + span: Span, } impl<'a, 'db, D: CoerceDelegate<'db>> ProofTreeVisitor<'db> for CoerceVisitor<'a, D> { type Result = ControlFlow<()>; + fn span(&self) -> Span { + self.span + } + fn visit_goal(&mut self, goal: &InspectGoal<'_, 'db>) -> Self::Result { let Some(pred) = goal.goal().predicate.as_trait_clause() else { return ControlFlow::Continue(()); diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index e179ca4bd3..a6c8cda404 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -27,7 +27,7 @@ use syntax::ast::RangeOp; use tracing::debug; use crate::{ - Adjust, Adjustment, CallableDefId, Rawness, consteval, + Adjust, Adjustment, CallableDefId, Rawness, Span, consteval, infer::{AllowTwoPhase, BreakableKind, coerce::CoerceMany, find_continuable, pat::PatOrigin}, lower::lower_mutability, method_resolution::{self, CandidateId, MethodCallee, MethodError}, @@ -176,7 +176,7 @@ impl<'db> InferenceContext<'_, 'db> { fn pat_guaranteed_to_constitute_read_for_never(&self, pat: PatId) -> bool { match &self.store[pat] { // Does not constitute a read. - Pat::Wild => false, + Pat::Wild | Pat::Rest => false, // This is unnecessarily restrictive when the pattern that doesn't // constitute a read is unreachable. @@ -343,7 +343,7 @@ impl<'db> InferenceContext<'_, 'db> { coercion_sites[1] = else_branch; } let mut coerce = CoerceMany::with_coercion_sites( - expected.coercion_target_type(&mut self.table), + expected.coercion_target_type(&mut self.table, then_branch.into()), &coercion_sites, ); coerce.coerce(self, &ObligationCause::new(), then_branch, then_ty, ExprIsRead::Yes); @@ -397,7 +397,7 @@ impl<'db> InferenceContext<'_, 'db> { .1 } &Expr::Loop { body, label } => { - let ty = expected.coercion_target_type(&mut self.table); + let ty = expected.coercion_target_type(&mut self.table, tgt_expr.into()); let (breaks, ()) = self.with_breakable_ctx(BreakableKind::Loop, Some(ty), label, |this| { this.infer_expr( @@ -466,7 +466,7 @@ impl<'db> InferenceContext<'_, 'db> { // We don't coerce to `()` so that if the match expression is a // statement it's branches can have any consistent type. Expectation::HasType(ty) if *ty != self.types.types.unit => *ty, - _ => self.table.next_ty_var(), + _ => self.table.next_ty_var((*expr).into()), }; let mut coerce = CoerceMany::new(result_ty); @@ -629,7 +629,7 @@ impl<'db> InferenceContext<'_, 'db> { match rawness { Rawness::RawPtr => Ty::new_ptr(self.interner(), inner_ty, mutability), Rawness::Ref => { - let lt = self.table.next_region_var(); + let lt = self.table.next_region_var(tgt_expr.into()); Ty::new_ref(self.interner(), lt, inner_ty, mutability) } } @@ -675,7 +675,7 @@ impl<'db> InferenceContext<'_, 'db> { // However, rustc lowers destructuring assignments into blocks, and blocks return `!` if they have no tail // expression and they diverge. Therefore, we have to do the same here, even though we don't lower destructuring // assignments into blocks. - self.table.new_maybe_never_var() + self.table.new_maybe_never_var(value.into()) } else { self.types.types.unit } @@ -731,7 +731,7 @@ impl<'db> InferenceContext<'_, 'db> { let idx_t = self.infer_expr_no_expect(*index, ExprIsRead::Yes); let base_t = self.structurally_resolve_type((*base).into(), base_t); - match self.lookup_indexing(tgt_expr, *base, base_t, idx_t) { + match self.lookup_indexing(tgt_expr, *base, *index, base_t, idx_t) { Some((trait_index_ty, trait_element_ty)) => { // two-phase not needed because index_ty is never mutable self.demand_coerce( @@ -755,10 +755,10 @@ impl<'db> InferenceContext<'_, 'db> { { Some(TyKind::Tuple(substs)) => substs .iter() - .chain(repeat_with(|| self.table.next_ty_var())) + .chain(repeat_with(|| self.table.next_ty_var(Span::Dummy))) .take(exprs.len()) .collect::<Vec<_>>(), - _ => (0..exprs.len()).map(|_| self.table.next_ty_var()).collect(), + _ => exprs.iter().map(|&expr| self.table.next_ty_var(expr.into())).collect(), }; for (expr, ty) in exprs.iter().zip(tys.iter_mut()) { @@ -768,7 +768,7 @@ impl<'db> InferenceContext<'_, 'db> { Ty::new_tup(self.interner(), &tys) } - Expr::Array(array) => self.infer_expr_array(array, expected), + Expr::Array(array) => self.infer_expr_array(tgt_expr, array, expected), Expr::Literal(lit) => match lit { Literal::Bool(..) => self.types.types.bool, Literal::String(..) => self.types.types.static_str_ref, @@ -1119,7 +1119,7 @@ impl<'db> InferenceContext<'_, 'db> { if self.features.type_changing_struct_update { if matches!(adt_id, AdtId::StructId(_)) { // Make some fresh generic parameters for our ADT type. - let fresh_args = self.table.fresh_args_for_item(adt_id.into()); + let fresh_args = self.table.fresh_args_for_item(expr.into(), adt_id.into()); // We do subtyping on the FRU fields first, so we can // learn exactly what types we expect the base expr // needs constrained to be compatible with the struct @@ -1266,7 +1266,7 @@ impl<'db> InferenceContext<'_, 'db> { // ...but otherwise we want to use any supertype of the // scrutinee. This is sort of a workaround, see note (*) in // `check_pat` for some details. - let scrut_ty = self.table.next_ty_var(); + let scrut_ty = self.table.next_ty_var(scrut.into()); self.infer_expr_coerce_never(scrut, &Expectation::HasType(scrut_ty), scrutinee_is_read); scrut_ty } @@ -1328,13 +1328,19 @@ impl<'db> InferenceContext<'_, 'db> { } oprnd_t } - fn infer_expr_array(&mut self, array: &Array, expected: &Expectation<'db>) -> Ty<'db> { + + fn infer_expr_array( + &mut self, + expr: ExprId, + array: &Array, + expected: &Expectation<'db>, + ) -> Ty<'db> { let elem_ty = match expected .to_option(&mut self.table) .map(|t| self.table.try_structurally_resolve_type(t).kind()) { Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st, - _ => self.table.next_ty_var(), + _ => self.table.next_ty_var(expr.into()), }; let krate = self.resolver.krate(); @@ -1371,7 +1377,7 @@ impl<'db> InferenceContext<'_, 'db> { let len = match self.store[repeat] { Expr::Underscore => { self.write_expr_ty(repeat, usize); - self.table.next_const_var() + self.table.next_const_var(repeat.into()) } _ => { self.infer_expr(repeat, &Expectation::HasType(usize), ExprIsRead::Yes); @@ -1383,7 +1389,7 @@ impl<'db> InferenceContext<'_, 'db> { } }; // Try to evaluate unevaluated constant, and insert variable if is not possible. - let len = self.table.insert_const_vars_shallow(len); + let len = self.insert_const_vars_shallow(len); Ty::new_array_with_const_len(self.interner(), elem_ty, len) } @@ -1477,7 +1483,7 @@ impl<'db> InferenceContext<'_, 'db> { label: Option<LabelId>, expected: &Expectation<'db>, ) -> Ty<'db> { - let coerce_ty = expected.coercion_target_type(&mut self.table); + let coerce_ty = expected.coercion_target_type(&mut self.table, expr.into()); let g = self.resolver.update_to_inner_scope(self.db, self.owner, expr); let (break_ty, ty) = @@ -1488,7 +1494,7 @@ impl<'db> InferenceContext<'_, 'db> { let decl_ty = type_ref .as_ref() .map(|&tr| this.make_body_ty(tr)) - .unwrap_or_else(|| this.table.next_ty_var()); + .unwrap_or_else(|| this.table.next_ty_var((*pat).into())); let ty = if let Some(expr) = initializer { // If we have a subpattern that performs a read, we want to consider this @@ -1561,7 +1567,7 @@ impl<'db> InferenceContext<'_, 'db> { // `!`). if this.diverges.is_always() { // we don't even make an attempt at coercion - this.table.new_maybe_never_var() + this.table.new_maybe_never_var(expr.into()) } else if let Some(t) = expected.only_has_type(&mut this.table) { if this .coerce( @@ -1728,10 +1734,13 @@ impl<'db> InferenceContext<'_, 'db> { fn instantiate_erroneous_method(&mut self, def_id: FunctionId) -> MethodCallee<'db> { // FIXME: Using fresh infer vars for the method args isn't optimal, // we can do better by going thorough the full probe/confirm machinery. - let args = self.table.fresh_args_for_item(def_id.into()); + let args = self.table.fresh_args_for_item(Span::Dummy, def_id.into()); let sig = self.db.callable_item_signature(def_id.into()).instantiate(self.interner(), args); - let sig = - self.infcx().instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, sig); + let sig = self.infcx().instantiate_binder_with_fresh_vars( + Span::Dummy, + BoundRegionConversionTime::FnCall, + sig, + ); MethodCallee { def_id, args, sig } } @@ -1810,20 +1819,21 @@ impl<'db> InferenceContext<'_, 'db> { None => None, }; - let assoc_func_with_same_name = self.with_method_resolution(|ctx| { - if !matches!( - receiver_ty.kind(), - TyKind::Infer(InferTy::TyVar(_)) | TyKind::Error(_) - ) { - ctx.probe_for_name( - method_resolution::Mode::Path, - method_name.clone(), - receiver_ty, - ) - } else { - Err(MethodError::ErrorReported) - } - }); + let assoc_func_with_same_name = + self.with_method_resolution(tgt_expr.into(), receiver.into(), |ctx| { + if !matches!( + receiver_ty.kind(), + TyKind::Infer(InferTy::TyVar(_)) | TyKind::Error(_) + ) { + ctx.probe_for_name( + method_resolution::Mode::Path, + method_name.clone(), + receiver_ty, + ) + } else { + Err(MethodError::ErrorReported) + } + }); let assoc_func_with_same_name = match assoc_func_with_same_name { Ok(method_resolution::Pick { item: CandidateId::FunctionId(def_id), .. @@ -1928,7 +1938,7 @@ impl<'db> InferenceContext<'_, 'db> { let formal_input_tys: Vec<_> = formal_input_tys .iter() .map(|&ty| { - let generalized_ty = self.table.next_ty_var(); + let generalized_ty = self.table.next_ty_var(call_expr.into()); let _ = self.demand_eqtype(call_expr.into(), ty, generalized_ty); generalized_ty }) diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs index b2369f6a87..c3b532638f 100644 --- a/crates/hir-ty/src/infer/mutability.rs +++ b/crates/hir-ty/src/infer/mutability.rs @@ -32,6 +32,7 @@ impl<'db> InferenceContext<'_, 'db> { }; if let Some(infer_ok) = Self::try_mutable_overloaded_place_op( &self.table, + tgt_expr, source_ty, None, PlaceOp::Deref, diff --git a/crates/hir-ty/src/infer/op.rs b/crates/hir-ty/src/infer/op.rs index 2916a46ca3..5900027a98 100644 --- a/crates/hir-ty/src/infer/op.rs +++ b/crates/hir-ty/src/infer/op.rs @@ -180,7 +180,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`. let lhs_ty = self.infer_expr_no_expect(lhs_expr, ExprIsRead::Yes); - let fresh_var = self.table.next_ty_var(); + let fresh_var = self.table.next_ty_var(lhs_expr.into()); self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No, ExprIsRead::Yes) } }; @@ -192,7 +192,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // using this variable as the expected type, which sometimes lets // us do better coercions than we would be able to do otherwise, // particularly for things like `String + &String`. - let rhs_ty_var = self.table.next_ty_var(); + let rhs_ty_var = self.table.next_ty_var(rhs_expr.into()); let result = self.lookup_op_method( lhs_ty, Some((rhs_expr, rhs_ty_var)), diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index 3cd7461cf3..ac209adef8 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -26,7 +26,7 @@ use span::Edition; use tracing::{debug, instrument, trace}; use crate::{ - BindingMode, InferenceDiagnostic, + BindingMode, InferenceDiagnostic, Span, infer::{ AllowTwoPhase, ByRef, Expectation, InferenceContext, PatAdjust, PatAdjustment, TypeMismatch, expr::ExprIsRead, @@ -446,7 +446,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> { pat_info, ) } - Pat::Missing | Pat::Wild => expected, + Pat::Missing => self.types.types.error, + Pat::Wild | Pat::Rest => expected, // We allow any type here; we ensure that the type is uninhabited during match checking. // Pat::Never => expected, Pat::Path(_) => { @@ -658,8 +659,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> { Pat::Ref { .. } // No need to do anything on a missing pattern. | Pat::Missing - // A `_` pattern works with any expected type, so there's no need to do anything. - | Pat::Wild + // A `_`/`..` pattern works with any expected type, so there's no need to do anything. + | Pat::Wild | Pat::Rest // Bindings also work with whatever the expected type is, // and moreover if we peel references off, that will give us the wrong binding type. // Also, we can have a subpattern `binding @ pat`. @@ -928,7 +929,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` // is required. However, we use equality, which is stronger. // See (note_1) for an explanation. - self.new_ref_ty(mutbl, expected) + self.new_ref_ty(pat.into(), mutbl, expected) } // Otherwise, the type of x is the expected type `T`. ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1). @@ -1110,7 +1111,9 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; } let max_len = cmp::max(expected_len, elements.len()); - let element_tys_iter = (0..max_len).map(|_| self.table.next_ty_var()); + let element_tys_iter = (0..max_len).map(|i| { + self.table.next_ty_var(elements.get(i).copied().map(Span::PatId).unwrap_or(Span::Dummy)) + }); let element_tys = Tys::new_from_iter(interner, element_tys_iter); let pat_ty = Ty::new(interner, TyKind::Tuple(element_tys)); if self.demand_eqtype(pat.into(), expected, pat_ty).is_err() { @@ -1249,7 +1252,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; .map(|()| { // Here, `demand::subtype` is good enough, but I don't // think any errors can be introduced by using `demand::eqtype`. - let inner_ty = self.table.next_ty_var(); + let inner_ty = self.table.next_ty_var(inner.into()); let box_ty = Ty::new_box(interner, inner_ty); _ = self.demand_eqtype(pat.into(), expected, box_ty); (box_ty, inner_ty) @@ -1472,8 +1475,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; (expected, r_ty) } _ => { - let inner_ty = self.table.next_ty_var(); - let ref_ty = self.new_ref_ty(pat_mutbl, inner_ty); + let inner_ty = self.table.next_ty_var(inner.into()); + let ref_ty = self.new_ref_ty(inner.into(), pat_mutbl, inner_ty); debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); _ = self.demand_eqtype(pat.into(), expected, ref_ty); @@ -1492,8 +1495,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; } /// Create a reference or pinned reference type with a fresh region variable. - fn new_ref_ty(&self, mutbl: Mutability, ty: Ty<'db>) -> Ty<'db> { - let region = self.table.next_region_var(); + fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'db>) -> Ty<'db> { + let region = self.table.next_region_var(span); Ty::new_ref(self.interner(), region, ty, mutbl) } @@ -1501,6 +1504,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; &self, before: &[PatId], slice: Option<PatId>, + pat: PatId, ) -> Option<Ty<'db>> { if slice.is_some() { return None; @@ -1508,7 +1512,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; let interner = self.interner(); let len = before.len(); - let inner_ty = self.table.next_ty_var(); + let inner_ty = self.table.next_ty_var(pat.into()); Some(Ty::new_array(interner, inner_ty, len.try_into().unwrap())) } @@ -1576,7 +1580,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; // to an array if the given pattern allows it. See issue #76342 if self.pat_is_irrefutable(pat_info.pat_origin) && expected.is_ty_var() - && let Some(resolved_arr_ty) = self.try_resolve_slice_ty_to_array_ty(before, slice) + && let Some(resolved_arr_ty) = self.try_resolve_slice_ty_to_array_ty(before, slice, pat) { debug!(?resolved_arr_ty); let _ = self.demand_eqtype(pat.into(), expected, resolved_arr_ty); diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 0687d56024..c020c9812b 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -11,7 +11,7 @@ use rustc_type_ir::inherent::{SliceLike, Ty as _}; use stdx::never; use crate::{ - InferenceDiagnostic, ValueTyDefId, + InferenceDiagnostic, Span, ValueTyDefId, infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, lower::{GenericPredicates, LifetimeElisionKind}, method_resolution::{self, CandidateId, MethodError}, @@ -38,7 +38,7 @@ impl<'db> InferenceContext<'_, 'db> { } ValuePathResolution::NonGeneric(ty) => return Some((value, ty)), }; - let args = self.insert_type_vars(substs); + let args = self.insert_type_vars(substs, id.into()); self.add_required_obligations_for_value_path(generic_def, args); @@ -91,7 +91,7 @@ impl<'db> InferenceContext<'_, 'db> { }; } ValueNs::GenericParam(it) => { - return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty_ns(it))); + return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty(it))); } }; @@ -157,12 +157,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(ty); + let ty = self.table.process_user_written_ty(type_ref.into(), ty); path_ctx.ignore_last_segment(); let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns, true); drop_ctx(ctx, no_diagnostics); - let ty = self.table.process_user_written_ty(ty); + let ty = self.table.process_user_written_ty(id.into(), 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); @@ -187,7 +187,7 @@ impl<'db> InferenceContext<'_, 'db> { let (resolution, substs) = match (def, is_before_last) { (TypeNs::TraitId(trait_), true) => { - let self_ty = self.table.next_ty_var(); + 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); drop_ctx(ctx, no_diagnostics); @@ -205,7 +205,7 @@ impl<'db> InferenceContext<'_, 'db> { return None; } - let ty = self.process_user_written_ty(ty); + let ty = self.process_user_written_ty(id.into(), ty); self.resolve_ty_assoc_item(ty, last_segment.name, id) } @@ -290,7 +290,7 @@ impl<'db> InferenceContext<'_, 'db> { return Some(result); } - let res = self.with_method_resolution(|ctx| { + let res = self.with_method_resolution(Span::Dummy, Span::Dummy, |ctx| { ctx.probe_for_name(method_resolution::Mode::Path, name.clone(), ty) }); let (item, visible) = match res { @@ -310,7 +310,7 @@ impl<'db> InferenceContext<'_, 'db> { }; let substs = match container { ItemContainerId::ImplId(impl_id) => { - let impl_substs = self.table.fresh_args_for_item(impl_id.into()); + let impl_substs = self.table.fresh_args_for_item(id.into(), impl_id.into()); let impl_self_ty = self.db.impl_self_ty(impl_id).instantiate(self.interner(), impl_substs); _ = self.demand_eqtype(id, impl_self_ty, ty); @@ -318,9 +318,12 @@ impl<'db> InferenceContext<'_, 'db> { } ItemContainerId::TraitId(trait_) => { // we're picking this method - GenericArgs::fill_rest(self.interner(), trait_.into(), [ty.into()], |_, id, _| { - self.table.next_var_for_param(id) - }) + GenericArgs::fill_rest( + self.interner(), + trait_.into(), + [ty.into()], + |_, param, _| self.table.var_for_def(param, id.into()), + ) } ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => { never!("assoc item contained in module/extern block"); diff --git a/crates/hir-ty/src/infer/place_op.rs b/crates/hir-ty/src/infer/place_op.rs index 1671b67d34..63841af682 100644 --- a/crates/hir-ty/src/infer/place_op.rs +++ b/crates/hir-ty/src/infer/place_op.rs @@ -29,9 +29,10 @@ pub(super) enum PlaceOp { impl<'a, 'db> InferenceContext<'a, 'db> { pub(super) fn try_overloaded_deref( &self, + expr: ExprId, base_ty: Ty<'db>, ) -> Option<InferOk<'db, MethodCallee<'db>>> { - self.try_overloaded_place_op(base_ty, None, PlaceOp::Deref) + self.try_overloaded_place_op(expr, base_ty, None, PlaceOp::Deref) } /// For the overloaded place expressions (`*x`, `x[3]`), the trait @@ -57,7 +58,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { return Some(ty); } - let ok = self.try_overloaded_deref(oprnd_ty)?; + let ok = self.try_overloaded_deref(expr, oprnd_ty)?; let method = self.table.register_infer_ok(ok); if let TyKind::Ref(_, _, Mutability::Not) = method.sig.inputs_and_output.inputs()[0].kind() { @@ -81,6 +82,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { &mut self, expr: ExprId, base_expr: ExprId, + index_expr: ExprId, base_ty: Ty<'db>, idx_ty: Ty<'db>, ) -> Option<(/*index type*/ Ty<'db>, /*element type*/ Ty<'db>)> { @@ -91,7 +93,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { let mut autoderef = InferenceContextAutoderef::new_from_inference_context(self, base_ty); let mut result = None; while result.is_none() && autoderef.next().is_some() { - result = Self::try_index_step(expr, base_expr, &mut autoderef, idx_ty); + result = Self::try_index_step(expr, base_expr, index_expr, &mut autoderef, idx_ty); } result } @@ -104,6 +106,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { fn try_index_step( expr: ExprId, base_expr: ExprId, + index_expr: ExprId, autoderef: &mut InferenceContextAutoderef<'_, 'a, 'db>, index_ty: Ty<'db>, ) -> Option<(/*index type*/ Ty<'db>, /*element type*/ Ty<'db>)> { @@ -136,9 +139,13 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // If some lookup succeeds, write callee into table and extract index/element // type from the method signature. // If some lookup succeeded, install method in table - let input_ty = autoderef.ctx().table.next_ty_var(); - let method = - autoderef.ctx().try_overloaded_place_op(self_ty, Some(input_ty), PlaceOp::Index); + let input_ty = autoderef.ctx().table.next_ty_var(index_expr.into()); + let method = autoderef.ctx().try_overloaded_place_op( + expr, + self_ty, + Some(input_ty), + PlaceOp::Index, + ); if let Some(result) = method { debug!("try_index_step: success, using overloaded indexing"); @@ -180,6 +187,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { /// `convert_place_derefs_to_mutable`. pub(super) fn try_overloaded_place_op( &self, + expr: ExprId, base_ty: Ty<'db>, opt_rhs_ty: Option<Ty<'db>>, op: PlaceOp, @@ -198,7 +206,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // opaque types as rigid here to support `impl Deref<Target = impl Index<usize>>`. let treat_opaques = TreatNotYetDefinedOpaques::AsInfer; self.table.lookup_method_for_operator( - ObligationCause::new(), + ObligationCause::with_span(expr.into()), imm_op, imm_tr, base_ty, @@ -209,6 +217,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { pub(super) fn try_mutable_overloaded_place_op( table: &InferenceTable<'db>, + expr: ExprId, base_ty: Ty<'db>, opt_rhs_ty: Option<Ty<'db>>, op: PlaceOp, @@ -230,7 +239,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // of the opaque. let treat_opaques = TreatNotYetDefinedOpaques::AsInfer; table.lookup_method_for_operator( - ObligationCause::new(), + ObligationCause::with_span(expr.into()), mut_op, mut_tr, base_ty, @@ -276,7 +285,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { )) } }; - let method = Self::try_mutable_overloaded_place_op(&self.table, base_ty, arg_ty, op); + let method = Self::try_mutable_overloaded_place_op(&self.table, expr, base_ty, arg_ty, op); let method = match method { Some(ok) => self.table.register_infer_ok(ok), // Couldn't find the mutable variant of the place op, keep the diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index be4d370c24..4342375621 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -7,12 +7,13 @@ use hir_def::{ExpressionStoreOwnerId, GenericParamId, TraitId}; use rustc_hash::FxHashSet; use rustc_type_ir::{ TyVid, TypeFoldable, TypeVisitableExt, - inherent::{Const as _, GenericArg as _, IntoKind, Ty as _}, + inherent::{GenericArg as _, IntoKind, Ty as _}, solve::Certainty, }; use smallvec::SmallVec; use crate::{ + Span, db::HirDatabase, next_solver::{ Canonical, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, @@ -41,6 +42,10 @@ struct NestedObligationsForSelfTy<'a, 'db> { impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> { type Result = (); + fn span(&self) -> Span { + self.root_cause.span() + } + fn config(&self) -> InspectConfig { // Using an intentionally low depth to minimize the chance of future // breaking changes in case we adapt the approach later on. This also @@ -112,7 +117,7 @@ fn could_unify_impl<'db>( let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); let cause = ObligationCause::dummy(); let at = infcx.at(&cause, env.param_env); - let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(tys); + let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(Span::Dummy, tys); let mut ctxt = ObligationCtxt::new(&infcx); let can_unify = at .eq(ty1_with_vars, ty2_with_vars) @@ -245,12 +250,12 @@ impl<'db> InferenceTable<'db> { self.diverging_type_vars.insert(ty); } - pub(crate) fn next_ty_var(&self) -> Ty<'db> { - self.infer_ctxt.next_ty_var() + pub(crate) fn next_ty_var(&self, span: Span) -> Ty<'db> { + self.infer_ctxt.next_ty_var(span) } - pub(crate) fn next_const_var(&self) -> Const<'db> { - self.infer_ctxt.next_const_var() + pub(crate) fn next_const_var(&self, span: Span) -> Const<'db> { + self.infer_ctxt.next_const_var(span) } pub(crate) fn next_int_var(&self) -> Ty<'db> { @@ -261,31 +266,18 @@ impl<'db> InferenceTable<'db> { self.infer_ctxt.next_float_var() } - pub(crate) fn new_maybe_never_var(&mut self) -> Ty<'db> { - let var = self.next_ty_var(); + pub(crate) fn new_maybe_never_var(&mut self, span: Span) -> Ty<'db> { + let var = self.next_ty_var(span); self.set_diverging(var); var } - pub(crate) fn next_region_var(&self) -> Region<'db> { - self.infer_ctxt.next_region_var() + pub(crate) fn next_region_var(&self, span: Span) -> Region<'db> { + self.infer_ctxt.next_region_var(span) } - pub(crate) fn next_var_for_param(&self, id: GenericParamId) -> GenericArg<'db> { - self.infer_ctxt.next_var_for_param(id) - } - - pub(crate) fn resolve_completely<T>(&mut self, value: T) -> T - where - T: TypeFoldable<DbInterner<'db>>, - { - let value = self.infer_ctxt.resolve_vars_if_possible(value); - - let mut goals = vec![]; - - // FIXME(next-solver): Handle `goals`. - - value.fold_with(&mut resolve_completely::Resolver::new(self, true, &mut goals)) + pub(crate) fn var_for_def(&self, id: GenericParamId, span: Span) -> GenericArg<'db> { + self.infer_ctxt.var_for_def(id, span) } pub(crate) fn at<'a>(&'a self, cause: &'a ObligationCause) -> At<'a, 'db> { @@ -319,8 +311,8 @@ impl<'db> InferenceTable<'db> { } /// Create a `GenericArgs` full of infer vars for `def`. - pub(crate) fn fresh_args_for_item(&self, def: SolverDefId) -> GenericArgs<'db> { - self.infer_ctxt.fresh_args_for_item(def) + pub(crate) fn fresh_args_for_item(&self, span: Span, def: SolverDefId) -> GenericArgs<'db> { + self.infer_ctxt.fresh_args_for_item(span, def) } /// Try to resolve `ty` to a structural type, normalizing aliases. @@ -399,19 +391,21 @@ impl<'db> InferenceTable<'db> { where I: IntoIterator<Item = PredicateObligation<'db>>, { - obligations.into_iter().for_each(|obligation| { - self.register_predicate(obligation); - }); + self.fulfillment_cx.register_predicate_obligations(&self.infer_ctxt, obligations); } /// checking later, during regionck, that `arg` is well-formed. pub(crate) fn register_wf_obligation(&mut self, term: Term<'db>, cause: ObligationCause) { - self.register_predicate(Obligation::new( - self.interner(), - cause, - self.param_env, - ClauseKind::WellFormed(term), - )); + let _ = (term, cause); + // FIXME: We don't currently register an obligation here because we don't implement + // wf checking anyway and this function is currently often passed dummy spans, which could + // prevent reporting "type annotation needed" errors. + // self.register_predicate(Obligation::new( + // self.interner(), + // cause, + // self.param_env, + // ClauseKind::WellFormed(term), + // )); } /// Registers obligations that all `args` are well-formed. @@ -421,34 +415,29 @@ impl<'db> InferenceTable<'db> { } } - pub(super) fn insert_type_vars<T>(&mut self, ty: T) -> T + pub(super) fn insert_type_vars<T>(&mut self, ty: T, span: Span) -> T where T: TypeFoldable<DbInterner<'db>>, { - self.infer_ctxt.insert_type_vars(ty) + self.infer_ctxt.insert_type_vars(ty, span) } /// Whenever you lower a user-written type, you should call this. - pub(crate) fn process_user_written_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { - self.process_remote_user_written_ty(ty) - // FIXME: Register a well-formed obligation. + 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(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); + let ty = self.insert_type_vars(ty, Span::Dummy); // 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`. // FIXME(next-solver): We should not deeply normalize here, only shallowly. self.try_structurally_resolve_type(ty) } - - /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it. - pub(super) fn insert_const_vars_shallow(&mut self, c: Const<'db>) -> Const<'db> { - if c.is_ct_error() { self.next_const_var() } else { c } - } } impl fmt::Debug for InferenceTable<'_> { @@ -460,20 +449,234 @@ impl fmt::Debug for InferenceTable<'_> { } } -mod resolve_completely { - use rustc_type_ir::{DebruijnIndex, Flags, TypeFolder, TypeSuperFoldable}; +pub(super) mod resolve_completely { + use rustc_hash::FxHashSet; + use rustc_type_ir::{ + DebruijnIndex, Flags, InferConst, InferTy, TypeFlags, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeVisitableExt, inherent::IntoKind, + }; + use stdx::never; + use thin_vec::ThinVec; use crate::{ - infer::unify::InferenceTable, + InferenceDiagnostic, Span, + infer::{TypeMismatch, unify::InferenceTable}, next_solver::{ - Const, DbInterner, Goal, Predicate, Region, Term, Ty, + Const, ConstKind, DbInterner, DefaultAny, GenericArg, Goal, Predicate, Region, Term, + TermKind, Ty, TyKind, infer::{resolve::ReplaceInferWithError, traits::ObligationCause}, normalize::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, }, }; + pub(crate) struct WriteBackCtxt<'db> { + table: InferenceTable<'db>, + diagnostics: ThinVec<InferenceDiagnostic>, + has_errors: bool, + spans_emitted_type_must_be_known_for: FxHashSet<Span>, + types: &'db DefaultAny<'db>, + } + + impl<'db> WriteBackCtxt<'db> { + pub(crate) fn new( + table: InferenceTable<'db>, + diagnostics: ThinVec<InferenceDiagnostic>, + vars_emitted_type_must_be_known_for: FxHashSet<Term<'db>>, + ) -> Self { + let spans_emitted_type_must_be_known_for = vars_emitted_type_must_be_known_for + .into_iter() + .filter_map(|term| match term.kind() { + TermKind::Ty(ty) => match ty.kind() { + TyKind::Infer(InferTy::TyVar(vid)) => { + Some(table.infer_ctxt.type_var_span(vid)) + } + _ => None, + }, + TermKind::Const(ct) => match ct.kind() { + ConstKind::Infer(InferConst::Var(vid)) => { + table.infer_ctxt.const_var_span(vid) + } + _ => None, + }, + }) + .collect(); + + Self { + types: table.interner().default_types(), + table, + diagnostics, + has_errors: false, + spans_emitted_type_must_be_known_for, + } + } + + pub(crate) fn resolve_type_mismatch(&mut self, value_ref: &mut TypeMismatch) { + // Ignore diagnostics from type mismatches, which are diagnostics themselves. + // FIXME: We should make type mismatches just regular diagnostics. + let prev_diagnostics_len = self.diagnostics.len(); + self.resolve_completely(value_ref); + self.diagnostics.truncate(prev_diagnostics_len); + } + + pub(crate) fn resolve_completely<T>(&mut self, value_ref: &mut T) + where + T: TypeFoldable<DbInterner<'db>>, + { + self.resolve_completely_with_default(value_ref, value_ref.clone()); + } + + pub(crate) fn resolve_completely_with_default<T>(&mut self, value_ref: &mut T, default: T) + where + T: TypeFoldable<DbInterner<'db>>, + { + let value = std::mem::replace(value_ref, default); + + let value = self.table.resolve_vars_if_possible(value); + + let mut goals = vec![]; + + // FIXME(next-solver): Handle `goals`. + + *value_ref = value.fold_with(&mut Resolver::new(self, true, &mut goals)); + } + + pub(crate) fn resolve_diagnostics(mut self) -> (ThinVec<InferenceDiagnostic>, bool) { + let has_errors = self.has_errors; + + // Ignore diagnostics made from resolving diagnostics. + let mut diagnostics = std::mem::take(&mut self.diagnostics); + diagnostics.retain_mut(|diagnostic| { + self.resolve_completely(diagnostic); + + if let InferenceDiagnostic::ExpectedFunction { found: ty, .. } + | InferenceDiagnostic::UnresolvedField { receiver: ty, .. } + | InferenceDiagnostic::UnresolvedMethodCall { receiver: ty, .. } = diagnostic + && ty.as_ref().references_non_lt_error() + { + false + } else { + true + } + }); + diagnostics.shrink_to_fit(); + + (diagnostics, has_errors) + } + } + + struct DiagnoseInferVars<'a, 'db> { + ctx: &'a mut WriteBackCtxt<'db>, + top_term: Term<'db>, + } + + impl<'db> DiagnoseInferVars<'_, 'db> { + const TYPE_FLAGS: TypeFlags = TypeFlags::HAS_INFER.union(TypeFlags::HAS_NON_REGION_ERROR); + + fn err_on_span(&mut self, span: Span) { + if !self.ctx.spans_emitted_type_must_be_known_for.insert(span) { + // Suppress duplicate diagnostics. + return; + } + + if span.is_dummy() { + return; + } + + // We have to be careful not to insert infer vars here, as we won't resolve this new diagnostic. + let top_term = self.top_term.fold_with(&mut ReplaceInferWithError::new(self.cx())); + self.ctx.diagnostics.push(InferenceDiagnostic::TypeMustBeKnown { + at_point: span, + top_term: Some(GenericArg::from(top_term).store()), + }); + } + } + + impl<'db> TypeFolder<DbInterner<'db>> for DiagnoseInferVars<'_, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.ctx.table.interner() + } + + fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { + if !t.has_type_flags(Self::TYPE_FLAGS) { + return t; + } + + match t.kind() { + TyKind::Error(_) => { + self.ctx.has_errors = true; + t + } + TyKind::Infer(infer_ty) => match infer_ty { + InferTy::TyVar(vid) => { + self.err_on_span(self.ctx.table.infer_ctxt.type_var_span(vid)); + self.ctx.has_errors = true; + self.ctx.types.types.error + } + InferTy::IntVar(_) => { + never!("fallback should have resolved all int vars"); + self.ctx.types.types.i32 + } + InferTy::FloatVar(_) => { + never!("fallback should have resolved all float vars"); + self.ctx.types.types.f64 + } + InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_) => { + never!("should not have fresh infer vars outside of caching"); + self.ctx.has_errors = true; + self.ctx.types.types.error + } + }, + _ => t.super_fold_with(self), + } + } + + fn fold_const(&mut self, c: Const<'db>) -> Const<'db> { + if !c.has_type_flags(Self::TYPE_FLAGS) { + return c; + } + + match c.kind() { + ConstKind::Error(_) => { + self.ctx.has_errors = true; + c + } + ConstKind::Infer(infer_ct) => match infer_ct { + InferConst::Var(vid) => { + if let Some(span) = self.ctx.table.infer_ctxt.const_var_span(vid) { + self.err_on_span(span); + } + self.ctx.has_errors = true; + self.ctx.types.consts.error + } + InferConst::Fresh(_) => { + never!("should not have fresh infer vars outside of caching"); + self.ctx.has_errors = true; + self.ctx.types.consts.error + } + }, + _ => c.super_fold_with(self), + } + } + + fn fold_predicate(&mut self, p: Predicate<'db>) -> Predicate<'db> { + if !p.has_type_flags(Self::TYPE_FLAGS) { + return p; + } + p.super_fold_with(self) + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + if r.is_var() { + // For now, we don't error on regions. + self.ctx.types.regions.error + } else { + r + } + } + } + pub(super) struct Resolver<'a, 'db> { - ctx: &'a mut InferenceTable<'db>, + ctx: &'a mut WriteBackCtxt<'db>, /// Whether we should normalize, disabled when resolving predicates. should_normalize: bool, nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>, @@ -481,7 +684,7 @@ mod resolve_completely { impl<'a, 'db> Resolver<'a, 'db> { pub(super) fn new( - ctx: &'a mut InferenceTable<'db>, + ctx: &'a mut WriteBackCtxt<'db>, should_normalize: bool, nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>, ) -> Resolver<'a, 'db> { @@ -498,7 +701,7 @@ mod resolve_completely { { let value = if self.should_normalize { let cause = ObligationCause::new(); - let at = self.ctx.at(&cause); + let at = self.ctx.table.at(&cause); let universes = vec![None; outer_exclusive_binder(value).as_usize()]; match deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( at, value, universes, @@ -516,17 +719,17 @@ mod resolve_completely { value }; - value.fold_with(&mut ReplaceInferWithError::new(self.ctx.interner())) + value.fold_with(&mut DiagnoseInferVars { ctx: self.ctx, top_term: value.into() }) } } - impl<'cx, 'db> TypeFolder<DbInterner<'db>> for Resolver<'cx, 'db> { + impl<'db> TypeFolder<DbInterner<'db>> for Resolver<'_, 'db> { fn cx(&self) -> DbInterner<'db> { - self.ctx.interner() + self.ctx.table.interner() } fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { - if r.is_var() { Region::error(self.ctx.interner()) } else { r } + if r.is_var() { self.ctx.types.regions.error } else { r } } fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 2973b970f3..4433dd6425 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -62,7 +62,10 @@ use std::{hash::Hash, ops::ControlFlow}; use hir_def::{ CallableDefId, ExpressionStoreOwnerId, GenericDefId, TypeAliasId, TypeOrConstParamId, - TypeParamId, resolver::TypeNs, type_ref::Rawness, + TypeParamId, + hir::{ExprId, ExprOrPatId, PatId}, + resolver::TypeNs, + type_ref::{Rawness, TypeRefId}, }; use hir_expand::name::Name; use indexmap::{IndexMap, map::Entry}; @@ -74,6 +77,7 @@ use rustc_type_ir::{ BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt, inherent::{IntoKind, Ty as _}, }; +use stdx::impl_from; use syntax::ast::{ConstArg, make}; use traits::FnTrait; @@ -541,7 +545,7 @@ pub fn callable_sig_from_fn_trait<'db>( let impls_trait = |trait_: FnTrait| { let mut ocx = ObligationCtxt::new(&infcx); - let tupled_args = infcx.next_ty_var(); + let tupled_args = infcx.next_ty_var(Span::Dummy); let args = GenericArgs::new_from_slice(&[self_ty.into(), tupled_args.into()]); let trait_id = trait_.get_id(lang_items)?; let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args); @@ -661,6 +665,42 @@ pub fn known_const_to_ast<'db>( Some(make::expr_const_value(konst.display(db, display_target).to_string().as_str())) } +/// A `Span` represents some location in lowered code - a type, expression or pattern. +/// +/// It has no meaning outside its body therefore it should not exit the pass it was created in +/// (e.g. inference). It is usually associated with a solver obligation or an infer var, which +/// should also not cross the pass they were created in. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Span { + ExprId(ExprId), + PatId(PatId), + TypeRefId(TypeRefId), + /// An unimportant location. Errors on this will be suppressed. + Dummy, +} +impl_from!(ExprId, PatId, TypeRefId for Span); + +impl From<ExprOrPatId> for Span { + fn from(value: ExprOrPatId) -> Self { + match value { + ExprOrPatId::ExprId(idx) => idx.into(), + ExprOrPatId::PatId(idx) => idx.into(), + } + } +} + +impl Span { + pub(crate) fn pick_best(a: Span, b: Span) -> Span { + // We prefer dummy spans to minimize the risk of false errors. + if b.is_dummy() { b } else { a } + } + + #[inline] + pub fn is_dummy(&self) -> bool { + matches!(self, Self::Dummy) + } +} + pub fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> { use std::env; use std::sync::LazyLock; diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 335aff2c1d..7325cd0ef8 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -2379,7 +2379,7 @@ fn push_const_arg_has_type_predicates<'db>( interner, ParamConst { id: param_id, index: (param_index + const_params_offset) as u32 }, ), - db.const_param_ty_ns(param_id), + db.const_param_ty(param_id), ) .upcast(interner), )); diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs index a364894539..d6b9c375fc 100644 --- a/crates/hir-ty/src/lower/path.rs +++ b/crates/hir-ty/src/lower/path.rs @@ -736,6 +736,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { fn provided_type_like_const( &mut self, + _type_ref: TypeRefId, const_ty: Ty<'db>, arg: TypeLikeConst<'_>, ) -> Const<'db> { @@ -1002,8 +1003,12 @@ pub(crate) trait GenericArgsLowerer<'db> { arg: &HirGenericArg, ) -> GenericArg<'db>; - fn provided_type_like_const(&mut self, const_ty: Ty<'db>, arg: TypeLikeConst<'_>) - -> Const<'db>; + fn provided_type_like_const( + &mut self, + type_ref: TypeRefId, + const_ty: Ty<'db>, + arg: TypeLikeConst<'_>, + ) -> Const<'db>; fn inferred_kind( &mut self, @@ -1225,7 +1230,8 @@ pub(crate) fn substs_from_args_and_bindings<'db>( panic!("unmatching param kinds"); }; let const_ty = const_param_ty_query(db, param_id); - substs.push(ctx.provided_type_like_const(const_ty, konst).into()); + substs + .push(ctx.provided_type_like_const(*type_ref, const_ty, konst).into()); args.next(); params.next(); } else { diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 25c2df0d9f..2c6c7ed9a5 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -36,7 +36,7 @@ use stdx::impl_from; use triomphe::Arc; use crate::{ - all_super_traits, + Span, all_super_traits, db::HirDatabase, infer::{InferenceContext, unify::InferenceTable}, lower::GenericPredicates, @@ -65,6 +65,8 @@ pub struct MethodResolutionContext<'a, 'db> { pub traits_in_scope: &'a FxHashSet<TraitId>, pub edition: Edition, pub features: &'a UnstableFeatures, + pub call_span: Span, + pub receiver_span: Span, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)] @@ -134,7 +136,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { receiver: ExprId, call_expr: ExprId, ) -> Result<(MethodCallee<'db>, bool), MethodError<'db>> { - let (pick, is_visible) = match self.lookup_probe(name, self_ty) { + let (pick, is_visible) = match self.lookup_probe(call_expr, receiver, name, self_ty) { Ok(it) => (it, true), Err(MethodError::PrivateMatch(it)) => { // FIXME: Report error. @@ -159,10 +161,12 @@ impl<'a, 'db> InferenceContext<'a, 'db> { #[instrument(level = "debug", skip(self))] pub(crate) fn lookup_probe( &self, + call_expr: ExprId, + receiver: ExprId, method_name: Name, self_ty: Ty<'db>, ) -> probe::PickResult<'db> { - self.with_method_resolution(|ctx| { + self.with_method_resolution(call_expr.into(), receiver.into(), |ctx| { let pick = ctx.probe_for_name(probe::Mode::MethodCall, method_name, self_ty)?; Ok(pick) }) @@ -170,6 +174,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> { pub(crate) fn with_method_resolution<R>( &self, + call_span: Span, + receiver_span: Span, f: impl FnOnce(&MethodResolutionContext<'_, 'db>) -> R, ) -> R { let traits_in_scope = self.get_traits_in_scope(); @@ -184,6 +190,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> { traits_in_scope, edition: self.edition, features: self.features, + call_span, + receiver_span, }; f(&ctx) } @@ -240,7 +248,7 @@ impl<'db> InferenceTable<'db> { // FIXME: We should stop passing `None` for the failure case // when probing for call exprs. I.e. `opt_rhs_ty` should always // be set when it needs to be. - self.next_var_for_param(param_id) + self.var_for_def(param_id, cause.span()) } } }, @@ -248,7 +256,7 @@ impl<'db> InferenceTable<'db> { let obligation = Obligation::new( self.interner(), - cause, + cause.clone(), self.param_env, TraitRef::new_from_args(self.interner(), trait_def_id.into(), args), ); @@ -291,9 +299,11 @@ impl<'db> InferenceTable<'db> { // with bound regions. let fn_sig = self.db.callable_item_signature(method_item.into()).instantiate(interner, args); - let fn_sig = self - .infer_ctxt - .instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, fn_sig); + let fn_sig = self.infer_ctxt.instantiate_binder_with_fresh_vars( + cause.span(), + BoundRegionConversionTime::FnCall, + fn_sig, + ); // Register obligations for the parameters. This will include the // `Self` parameter, which in turn has a bound of the main trait, diff --git a/crates/hir-ty/src/method_resolution/confirm.rs b/crates/hir-ty/src/method_resolution/confirm.rs index 3bdef44dd3..a29e3db18d 100644 --- a/crates/hir-ty/src/method_resolution/confirm.rs +++ b/crates/hir-ty/src/method_resolution/confirm.rs @@ -5,6 +5,7 @@ use hir_def::{ FunctionId, GenericDefId, GenericParamId, ItemContainerId, TraitId, expr_store::path::{GenericArg as HirGenericArg, GenericArgs as HirGenericArgs}, hir::{ExprId, generics::GenericParamDataRef}, + type_ref::TypeRefId, }; use rustc_type_ir::{ TypeFoldable, @@ -15,7 +16,7 @@ use tracing::debug; use crate::{ Adjust, Adjustment, AutoBorrow, IncorrectGenericsLenKind, InferenceDiagnostic, - LifetimeElisionKind, PointerCast, + LifetimeElisionKind, PointerCast, Span, db::HirDatabase, infer::{AllowTwoPhase, AutoBorrowMutability, InferenceContext, TypeMismatch}, lower::{ @@ -190,7 +191,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { self.ctx.table.register_infer_ok(autoderef.adjust_steps_as_infer_ok()); match pick.autoref_or_ptr_adjustment { Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => { - let region = self.infcx().next_region_var(); + let region = self.infcx().next_region_var(self.expr.into()); // Type we're wrapping in a reference, used later for unsizing let base_ty = target; @@ -254,7 +255,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { ) -> GenericArgs<'db> { match pick.kind { probe::InherentImplPick(impl_def_id) => { - self.infcx().fresh_args_for_item(impl_def_id.into()) + self.infcx().fresh_args_for_item(self.expr.into(), impl_def_id.into()) } probe::ObjectPick(trait_def_id) => { @@ -296,7 +297,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { // the process we will unify the transformed-self-type // of the method with the actual type in order to // unify some of these variables. - self.infcx().fresh_args_for_item(trait_def_id.into()) + self.infcx().fresh_args_for_item(self.expr.into(), trait_def_id.into()) } probe::WhereClausePick(poly_trait_ref) => { @@ -400,7 +401,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { let GenericParamId::ConstParamId(const_id) = param_id else { unreachable!("non-const param ID for const param"); }; - let const_ty = self.ctx.db.const_param_ty_ns(const_id); + let const_ty = self.ctx.db.const_param_ty(const_id); self.ctx.make_body_const(*konst, const_ty).into() } _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"), @@ -409,12 +410,15 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { fn provided_type_like_const( &mut self, + type_ref: TypeRefId, const_ty: Ty<'db>, arg: TypeLikeConst<'_>, ) -> Const<'db> { match arg { - TypeLikeConst::Path(path) => self.ctx.make_path_as_body_const(path, const_ty), - TypeLikeConst::Infer => self.ctx.table.next_const_var(), + TypeLikeConst::Path(path) => { + self.ctx.make_path_as_body_const(type_ref, path, const_ty) + } + TypeLikeConst::Infer => self.ctx.table.next_const_var(Span::Dummy), } } @@ -428,7 +432,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { ) -> 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.next_var_for_param(param_id) + self.ctx.table.var_for_def(param_id, Span::Dummy) } fn parent_arg(&mut self, param_idx: u32, _param_id: GenericParamId) -> GenericArg<'db> { @@ -609,6 +613,10 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { where T: TypeFoldable<DbInterner<'db>> + Copy, { - self.infcx().instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, value) + self.infcx().instantiate_binder_with_fresh_vars( + self.expr.into(), + BoundRegionConversionTime::FnCall, + value, + ) } } diff --git a/crates/hir-ty/src/method_resolution/probe.rs b/crates/hir-ty/src/method_resolution/probe.rs index afdc62183e..8a28b16724 100644 --- a/crates/hir-ty/src/method_resolution/probe.rs +++ b/crates/hir-ty/src/method_resolution/probe.rs @@ -284,7 +284,8 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> { // special handling for this "trivial case" is a good idea. let infcx = self.infcx; - let (self_ty, var_values) = infcx.instantiate_canonical(&query_input); + let (self_ty, var_values) = + infcx.instantiate_canonical(self.call_span, &query_input); debug!(?self_ty, ?query_input, "probe_op: Mode::Path"); let prev_opaque_entries = self.infcx.inner.borrow_mut().opaque_types().num_entries(); @@ -380,7 +381,8 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> { // chain to support recursive calls. We do error if the final // infer var is not an opaque. let infcx = self.infcx; - let (self_ty, inference_vars) = infcx.instantiate_canonical(self_ty); + let (self_ty, inference_vars) = + infcx.instantiate_canonical(self.receiver_span, self_ty); let prev_opaque_entries = infcx.inner.borrow_mut().opaque_types().num_entries(); let self_ty_is_opaque = |ty: Ty<'_>| { @@ -921,7 +923,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { // will still match the original object type, but it won't pollute our // type variables in any form, so just do that! let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) = - self.infcx().instantiate_canonical(self_ty); + self.infcx().instantiate_canonical(self.ctx.call_span, self_ty); self.assemble_inherent_candidates_from_object(generalized_self_ty); self.assemble_inherent_impl_candidates_for_type( @@ -1117,7 +1119,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { #[instrument(level = "debug", skip(self))] fn assemble_extension_candidates_for_trait(&mut self, trait_def_id: TraitId) { - let trait_args = self.infcx().fresh_args_for_item(trait_def_id.into()); + let trait_args = self.infcx().fresh_args_for_item(self.ctx.call_span, trait_def_id.into()); let trait_ref = TraitRef::new_from_args(self.interner(), trait_def_id.into(), trait_args); self.with_trait_item(trait_def_id, |this, item| { @@ -1510,6 +1512,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { } TraitCandidate(trait_ref) => self.infcx().probe(|_| { let trait_ref = self.infcx().instantiate_binder_with_fresh_vars( + self.ctx.call_span, BoundRegionConversionTime::FnCall, trait_ref, ); @@ -1574,7 +1577,8 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { match probe.kind { InherentImplCandidate { impl_def_id, .. } => { - let impl_args = self.infcx().fresh_args_for_item(impl_def_id.into()); + let impl_args = + self.infcx().fresh_args_for_item(self.ctx.call_span, impl_def_id.into()); let impl_ty = self.db().impl_self_ty(impl_def_id).instantiate(self.interner(), impl_args); (xform_self_ty, xform_ret_ty) = @@ -1632,6 +1636,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { } let trait_ref = self.infcx().instantiate_binder_with_fresh_vars( + self.ctx.call_span, BoundRegionConversionTime::FnCall, poly_trait_ref, ); @@ -1667,6 +1672,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { } ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => { let trait_ref = self.infcx().instantiate_binder_with_fresh_vars( + self.ctx.call_span, BoundRegionConversionTime::FnCall, poly_trait_ref, ); @@ -2029,8 +2035,12 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { // In general, during probe we erase regions. Region::new_erased(self.interner()).into() } - GenericParamId::TypeParamId(_) => self.infcx().next_ty_var().into(), - GenericParamId::ConstParamId(_) => self.infcx().next_const_var().into(), + GenericParamId::TypeParamId(_) => { + self.infcx().next_ty_var(self.ctx.call_span).into() + } + GenericParamId::ConstParamId(_) => { + self.infcx().next_const_var(self.ctx.call_span).into() + } } } }, diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index b935a6ed32..49fb6f5305 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -581,7 +581,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { ParamConst { id: p, index }, ) .store(), - ty: self.db.const_param_ty_ns(p).store(), + ty: self.db.const_param_ty(p).store(), }, span: None, }), diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs index 68b1c8b3b6..03c608f4b2 100644 --- a/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -132,7 +132,7 @@ impl<'db> MirLowerCtx<'_, 'db> { .into(), ); Ok(match &self.store[pattern] { - Pat::Missing => return Err(MirLowerError::IncompletePattern), + Pat::Missing | Pat::Rest => return Err(MirLowerError::IncompletePattern), Pat::Wild => (current, current_else), Pat::Tuple { args, ellipsis } => { let subst = match self.infer.pat_ty(pattern).kind() { diff --git a/crates/hir-ty/src/next_solver/format_proof_tree.rs b/crates/hir-ty/src/next_solver/format_proof_tree.rs index 66da6d5400..4b2f66a17d 100644 --- a/crates/hir-ty/src/next_solver/format_proof_tree.rs +++ b/crates/hir-ty/src/next_solver/format_proof_tree.rs @@ -3,7 +3,7 @@ use serde_derive::{Deserialize, Serialize}; use crate::next_solver::inspect::{InspectCandidate, InspectGoal}; use crate::next_solver::{AnyImplId, infer::InferCtxt}; -use crate::next_solver::{DbInterner, Span}; +use crate::{Span, next_solver::DbInterner}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProofTreeData { @@ -59,7 +59,7 @@ impl<'a, 'db> ProofTreeSerializer<'a, 'db> { let mut nested = Vec::new(); self.infcx.probe(|_| { - for nested_goal in candidate.instantiate_nested_goals() { + for nested_goal in candidate.instantiate_nested_goals(Span::Dummy) { nested.push(self.serialize_goal(&nested_goal)); } }); diff --git a/crates/hir-ty/src/next_solver/fulfill.rs b/crates/hir-ty/src/next_solver/fulfill.rs index cd0cb59760..ba9cd39d44 100644 --- a/crates/hir-ty/src/next_solver/fulfill.rs +++ b/crates/hir-ty/src/next_solver/fulfill.rs @@ -9,17 +9,20 @@ use rustc_next_trait_solver::{ }; use rustc_type_ir::{ Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, - inherent::{IntoKind, Span as _}, + inherent::IntoKind, solve::{Certainty, NoSolution}, }; -use crate::next_solver::{ - DbInterner, SolverContext, SolverDefId, Span, Ty, TyKind, TypingMode, - infer::{ - InferCtxt, - traits::{PredicateObligation, PredicateObligations}, +use crate::{ + Span, + next_solver::{ + DbInterner, SolverContext, SolverDefId, Ty, TyKind, TypingMode, + infer::{ + InferCtxt, + traits::{PredicateObligation, PredicateObligations}, + }, + inspect::ProofTreeVisitor, }, - inspect::ProofTreeVisitor, }; type PendingObligations<'db> = @@ -97,7 +100,7 @@ impl<'db> ObligationStorage<'db> { let goal = o.as_goal(); let result = <&SolverContext<'db>>::from(infcx).evaluate_root_goal( goal, - Span::dummy(), + o.cause.span(), stalled_on.take(), ); matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. })) @@ -169,7 +172,9 @@ impl<'db> FulfillmentCtxt<'db> { let goal = obligation.as_goal(); let delegate = <&SolverContext<'db>>::from(infcx); - if let Some(certainty) = delegate.compute_goal_fast_path(goal, Span::dummy()) { + if let Some(certainty) = + delegate.compute_goal_fast_path(goal, obligation.cause.span()) + { match certainty { Certainty::Yes => {} Certainty::Maybe { .. } => { @@ -179,9 +184,11 @@ impl<'db> FulfillmentCtxt<'db> { continue; } - let result = delegate.evaluate_root_goal(goal, Span::dummy(), stalled_on); + let result = delegate.evaluate_root_goal(goal, obligation.cause.span(), stalled_on); infcx.inspect_evaluated_obligation(&obligation, &result, || { - Some(delegate.evaluate_root_goal_for_proof_tree(goal, Span::dummy()).1) + Some( + delegate.evaluate_root_goal_for_proof_tree(goal, obligation.cause.span()).1, + ) }); let GoalEvaluation { goal: _, certainty, has_changed, stalled_on } = match result { Ok(result) => result, @@ -259,6 +266,7 @@ impl<'db> FulfillmentCtxt<'db> { obl.as_goal(), &mut StalledOnCoroutines { stalled_coroutines, + span: obl.cause.span(), cache: Default::default(), }, ) @@ -280,12 +288,17 @@ impl<'db> FulfillmentCtxt<'db> { /// so we want to keep this visitor *precise* too. pub struct StalledOnCoroutines<'a, 'db> { pub stalled_coroutines: &'a [SolverDefId], + pub span: Span, pub cache: FxHashSet<Ty<'db>>, } impl<'db> ProofTreeVisitor<'db> for StalledOnCoroutines<'_, 'db> { type Result = ControlFlow<()>; + fn span(&self) -> Span { + self.span + } + fn visit_goal(&mut self, inspect_goal: &super::inspect::InspectGoal<'_, 'db>) -> Self::Result { inspect_goal.goal().predicate.visit_with(self)?; diff --git a/crates/hir-ty/src/next_solver/generic_arg.rs b/crates/hir-ty/src/next_solver/generic_arg.rs index 72cf2f9f07..05955d060b 100644 --- a/crates/hir-ty/src/next_solver/generic_arg.rs +++ b/crates/hir-ty/src/next_solver/generic_arg.rs @@ -194,6 +194,25 @@ impl std::fmt::Debug for StoredGenericArg { } } +impl<'db> TypeVisitable<DbInterner<'db>> for StoredGenericArg { + fn visit_with<V: TypeVisitor<DbInterner<'db>>>(&self, visitor: &mut V) -> V::Result { + self.as_ref().visit_with(visitor) + } +} + +impl<'db> TypeFoldable<DbInterner<'db>> for StoredGenericArg { + fn try_fold_with<F: FallibleTypeFolder<DbInterner<'db>>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + Ok(self.as_ref().try_fold_with(folder)?.store()) + } + + fn fold_with<F: TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self { + self.as_ref().fold_with(folder).store() + } +} + #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct GenericArg<'db> { ptr: GenericArgImpl<'db>, @@ -457,6 +476,25 @@ impl_foldable_for_interned_slice!(GenericArgs); impl<'db> rustc_type_ir::inherent::GenericArg<DbInterner<'db>> for GenericArg<'db> {} +impl<'db> TypeVisitable<DbInterner<'db>> for StoredGenericArgs { + fn visit_with<V: TypeVisitor<DbInterner<'db>>>(&self, visitor: &mut V) -> V::Result { + self.as_ref().visit_with(visitor) + } +} + +impl<'db> TypeFoldable<DbInterner<'db>> for StoredGenericArgs { + fn try_fold_with<F: FallibleTypeFolder<DbInterner<'db>>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + Ok(self.as_ref().try_fold_with(folder)?.store()) + } + + fn fold_with<F: TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self { + self.as_ref().fold_with(folder).store() + } +} + impl<'db> GenericArgs<'db> { /// Creates an `GenericArgs` for generic parameter definitions, /// by calling closures to obtain each kind. diff --git a/crates/hir-ty/src/next_solver/infer/at.rs b/crates/hir-ty/src/next_solver/infer/at.rs index dc0b584084..4784edf60f 100644 --- a/crates/hir-ty/src/next_solver/infer/at.rs +++ b/crates/hir-ty/src/next_solver/infer/at.rs @@ -28,13 +28,12 @@ use rustc_type_ir::{ FnSig, GenericArgKind, TypeFoldable, TypingMode, Variance, error::ExpectedFound, - inherent::Span as _, relate::{Relate, TypeRelation, solver_relating::RelateExt}, }; use crate::next_solver::{ AliasTerm, AliasTy, Binder, Const, DbInterner, GenericArg, Goal, ParamEnv, - PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, Predicate, Region, Span, Term, + PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, Predicate, Region, Term, TraitRef, Ty, fulfill::NextSolverError, infer::relate::lattice::{LatticeOp, LatticeOpKind}, @@ -109,7 +108,7 @@ impl<'a, 'db> At<'a, 'db> { expected, Variance::Contravariant, actual, - Span::dummy(), + self.cause.span(), ) .map(|goals| self.goals_to_obligations(goals)) } @@ -125,7 +124,7 @@ impl<'a, 'db> At<'a, 'db> { expected, Variance::Covariant, actual, - Span::dummy(), + self.cause.span(), ) .map(|goals| self.goals_to_obligations(goals)) } @@ -141,7 +140,7 @@ impl<'a, 'db> At<'a, 'db> { expected, Variance::Invariant, actual, - Span::dummy(), + self.cause.span(), ) .map(|goals| self.goals_to_obligations(goals)) } diff --git a/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs b/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs index 1738552a8e..bda418cf20 100644 --- a/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs +++ b/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs @@ -404,13 +404,17 @@ impl<'db> InferCtxt<'db> { if kind.universe() != UniverseIndex::ROOT { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all, we have to deal with them for now. - self.instantiate_canonical_var(kind, var_values, |u| universe_map[u.as_usize()]) + self.instantiate_canonical_var(cause.span(), kind, var_values, |u| { + universe_map[u.as_usize()] + }) } else if kind.is_existential() { match opt_values[BoundVar::new(var_values.len())] { Some(k) => k, - None => self.instantiate_canonical_var(kind, var_values, |u| { - universe_map[u.as_usize()] - }), + None => { + self.instantiate_canonical_var(cause.span(), kind, var_values, |u| { + universe_map[u.as_usize()] + }) + } } } else { // For placeholders which were already part of the input, we simply map this diff --git a/crates/hir-ty/src/next_solver/infer/canonical/mod.rs b/crates/hir-ty/src/next_solver/infer/canonical/mod.rs index 1fefc0f265..a5e29e7836 100644 --- a/crates/hir-ty/src/next_solver/infer/canonical/mod.rs +++ b/crates/hir-ty/src/next_solver/infer/canonical/mod.rs @@ -21,10 +21,13 @@ //! //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html -use crate::next_solver::{ - ArgOutlivesPredicate, Canonical, CanonicalVarValues, Const, DbInterner, GenericArg, - OpaqueTypeKey, PlaceholderConst, PlaceholderRegion, PlaceholderType, Region, Ty, TyKind, - infer::InferCtxt, +use crate::{ + Span, + next_solver::{ + ArgOutlivesPredicate, Canonical, CanonicalVarValues, Const, DbInterner, GenericArg, + OpaqueTypeKey, PlaceholderConst, PlaceholderRegion, PlaceholderType, Region, Ty, TyKind, + infer::InferCtxt, + }, }; use instantiate::CanonicalExt; use macros::{TypeFoldable, TypeVisitable}; @@ -50,6 +53,7 @@ impl<'db> InferCtxt<'db> { /// for each of the canonical inputs to your query. pub fn instantiate_canonical<T>( &self, + span: Span, canonical: &Canonical<'db, T>, ) -> (T, CanonicalVarValues<'db>) where @@ -71,7 +75,9 @@ impl<'db> InferCtxt<'db> { let var_values = CanonicalVarValues::instantiate( self.interner, canonical.var_kinds, - |var_values, info| self.instantiate_canonical_var(info, var_values, |ui| universes[ui]), + |var_values, info| { + self.instantiate_canonical_var(span, info, var_values, |ui| universes[ui]) + }, ); let result = canonical.instantiate(self.interner, &var_values); (result, var_values) @@ -87,13 +93,14 @@ impl<'db> InferCtxt<'db> { /// We should somehow deduplicate all of this. pub fn instantiate_canonical_var( &self, + span: Span, cv_info: CanonicalVarKind<DbInterner<'db>>, previous_var_values: &[GenericArg<'db>], universe_map: impl Fn(UniverseIndex) -> UniverseIndex, ) -> GenericArg<'db> { match cv_info { CanonicalVarKind::Ty { ui, sub_root } => { - let vid = self.next_ty_var_id_in_universe(universe_map(ui)); + let vid = self.next_ty_var_id_in_universe(universe_map(ui), span); // If this inference variable is related to an earlier variable // via subtyping, we need to add that info to the inference context. if let Some(prev) = previous_var_values.get(sub_root.as_usize()) { @@ -117,7 +124,7 @@ impl<'db> InferCtxt<'db> { } CanonicalVarKind::Region(ui) => { - self.next_region_var_in_universe(universe_map(ui)).into() + self.next_region_var_in_universe(universe_map(ui), span).into() } CanonicalVarKind::PlaceholderRegion(PlaceholderRegion { universe, bound, .. }) => { @@ -126,7 +133,9 @@ impl<'db> InferCtxt<'db> { Region::new_placeholder(self.interner, placeholder_mapped).into() } - CanonicalVarKind::Const(ui) => self.next_const_var_in_universe(universe_map(ui)).into(), + CanonicalVarKind::Const(ui) => { + self.next_const_var_in_universe(universe_map(ui), span).into() + } CanonicalVarKind::PlaceholderConst(PlaceholderConst { universe, bound, .. }) => { let universe_mapped = universe_map(universe); let placeholder_mapped = PlaceholderConst::new(universe_mapped, bound); diff --git a/crates/hir-ty/src/next_solver/infer/context.rs b/crates/hir-ty/src/next_solver/infer/context.rs index 397986e2ed..9ea4665000 100644 --- a/crates/hir-ty/src/next_solver/infer/context.rs +++ b/crates/hir-ty/src/next_solver/infer/context.rs @@ -7,10 +7,13 @@ use rustc_type_ir::{ relate::combine::PredicateEmittingRelation, }; -use crate::next_solver::{ - Binder, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, OpaqueTypeKey, Region, - SolverDefId, Span, Ty, TyKind, - infer::opaque_types::{OpaqueHiddenType, table::OpaqueTypeStorageEntries}, +use crate::{ + Span, + next_solver::{ + Binder, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, OpaqueTypeKey, Region, + SolverDefId, Ty, TyKind, + infer::opaque_types::{OpaqueHiddenType, table::OpaqueTypeStorageEntries}, + }, }; use super::{BoundRegionConversionTime, InferCtxt, relate::RelateResult}; @@ -139,26 +142,30 @@ impl<'db> rustc_type_ir::InferCtxtLike for InferCtxt<'db> { } fn next_ty_infer(&self) -> Ty<'db> { - self.next_ty_var() + self.next_ty_var(Span::Dummy) } fn next_region_infer(&self) -> <Self::Interner as rustc_type_ir::Interner>::Region { - self.next_region_var() + self.next_region_var(Span::Dummy) } fn next_const_infer(&self) -> Const<'db> { - self.next_const_var() + self.next_const_var(Span::Dummy) } fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> { - self.fresh_args_for_item(def_id) + self.fresh_args_for_item(Span::Dummy, def_id) } fn instantiate_binder_with_infer<T: TypeFoldable<DbInterner<'db>> + Clone>( &self, value: Binder<'db, T>, ) -> T { - self.instantiate_binder_with_fresh_vars(BoundRegionConversionTime::HigherRankedType, value) + self.instantiate_binder_with_fresh_vars( + Span::Dummy, + BoundRegionConversionTime::HigherRankedType, + value, + ) } fn enter_forall<T: TypeFoldable<DbInterner<'db>> + Clone, U>( diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs index 1eacc295c9..f038c47a8b 100644 --- a/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/crates/hir-ty/src/next_solver/infer/mod.rs @@ -28,16 +28,18 @@ use rustc_type_ir::{ use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use traits::{ObligationCause, PredicateObligations}; -use type_variable::TypeVariableOrigin; -use unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; +use unify_key::{ConstVariableValue, ConstVidKey}; pub use crate::next_solver::infer::traits::ObligationInspector; -use crate::next_solver::{ - ArgOutlivesPredicate, BoundConst, BoundRegion, BoundTy, BoundVariableKind, Goal, Predicate, - SolverContext, - fold::BoundVarReplacerDelegate, - infer::{at::ToTrace, select::EvaluationResult, traits::PredicateObligation}, - obligation_ctxt::ObligationCtxt, +use crate::{ + Span, + next_solver::{ + ArgOutlivesPredicate, BoundConst, BoundRegion, BoundTy, BoundVariableKind, Goal, Predicate, + SolverContext, + fold::BoundVarReplacerDelegate, + infer::{at::ToTrace, select::EvaluationResult, traits::PredicateObligation}, + obligation_ctxt::ObligationCtxt, + }, }; use super::{ @@ -364,13 +366,14 @@ impl<'db> InferCtxtBuilder<'db> { /// (in other words, `S(C) = V`). pub fn build_with_canonical<T>( mut self, + span: Span, input: &CanonicalQueryInput<'db, T>, ) -> (InferCtxt<'db>, T, CanonicalVarValues<'db>) where T: TypeFoldable<DbInterner<'db>>, { let infcx = self.build(input.typing_mode.0); - let (value, args) = infcx.instantiate_canonical(&input.canonical); + let (value, args) = infcx.instantiate_canonical(span, &input.canonical); (infcx, value, args) } @@ -427,12 +430,13 @@ impl<'db> InferCtxt<'db> { )) } - pub(crate) fn insert_type_vars<T>(&self, ty: T) -> T + pub(crate) fn insert_type_vars<T>(&self, ty: T, span: Span) -> 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> { @@ -444,7 +448,11 @@ impl<'db> InferCtxt<'db> { return ty; } - if ty.is_ty_error() { self.infcx.next_ty_var() } else { ty.super_fold_with(self) } + if ty.is_ty_error() { + self.infcx.next_ty_var(self.span) + } else { + ty.super_fold_with(self) + } } fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { @@ -453,18 +461,18 @@ impl<'db> InferCtxt<'db> { } if ct.is_ct_error() { - self.infcx.next_const_var() + self.infcx.next_const_var(self.span) } 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() } else { r } + if r.is_error() { self.infcx.next_region_var(self.span) } else { r } } } - ty.fold_with(&mut Folder { infcx: self }) + ty.fold_with(&mut Folder { infcx: self, span }) } /// Evaluates whether the predicate can be satisfied in the given @@ -737,80 +745,49 @@ impl<'db> InferCtxt<'db> { self.inner.borrow_mut().type_variables().num_vars() } - pub fn next_var_for_param(&self, id: GenericParamId) -> GenericArg<'db> { - match id { - GenericParamId::TypeParamId(_) => self.next_ty_var().into(), - GenericParamId::ConstParamId(_) => self.next_const_var().into(), - GenericParamId::LifetimeParamId(_) => self.next_region_var().into(), - } + pub fn next_ty_var(&self, span: Span) -> Ty<'db> { + let vid = self.next_ty_vid(span); + Ty::new_var(self.interner, vid) } - pub fn next_ty_var(&self) -> Ty<'db> { - self.next_ty_var_with_origin(TypeVariableOrigin { param_def_id: None }) + pub fn next_ty_vid(&self, span: Span) -> TyVid { + self.next_ty_var_id_in_universe(self.universe(), span) } - pub fn next_ty_vid(&self) -> TyVid { - self.inner - .borrow_mut() - .type_variables() - .new_var(self.universe(), TypeVariableOrigin { param_def_id: None }) + pub fn next_ty_var_id_in_universe(&self, universe: UniverseIndex, span: Span) -> TyVid { + self.inner.borrow_mut().type_variables().new_var(universe, span) } - pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'db> { - let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin); + pub fn next_ty_var_in_universe(&self, universe: UniverseIndex, span: Span) -> Ty<'db> { + let vid = self.next_ty_var_id_in_universe(universe, span); Ty::new_var(self.interner, vid) } - pub fn next_ty_var_id_in_universe(&self, universe: UniverseIndex) -> TyVid { - let origin = TypeVariableOrigin { param_def_id: None }; - self.inner.borrow_mut().type_variables().new_var(universe, origin) - } - - pub fn next_ty_var_in_universe(&self, universe: UniverseIndex) -> Ty<'db> { - let vid = self.next_ty_var_id_in_universe(universe); - Ty::new_var(self.interner, vid) + pub fn next_const_var(&self, span: Span) -> Const<'db> { + let vid = self.next_const_vid(span); + Const::new_var(self.interner, vid) } - pub fn next_const_var(&self) -> Const<'db> { - self.next_const_var_with_origin(ConstVariableOrigin {}) + pub fn next_const_vid(&self, span: Span) -> ConstVid { + self.next_const_vid_in_universe(self.universe(), span) } - pub fn next_const_vid(&self) -> ConstVid { + pub fn next_const_vid_in_universe(&self, universe: UniverseIndex, span: Span) -> ConstVid { self.inner .borrow_mut() .const_unification_table() - .new_key(ConstVariableValue::Unknown { - origin: ConstVariableOrigin {}, - universe: self.universe(), - }) + .new_key(ConstVariableValue::Unknown { span, universe }) .vid } - pub fn next_const_var_with_origin(&self, origin: ConstVariableOrigin) -> Const<'db> { - let vid = self - .inner - .borrow_mut() - .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) - .vid; - Const::new_var(self.interner, vid) - } - - pub fn next_const_var_in_universe(&self, universe: UniverseIndex) -> Const<'db> { - let origin = ConstVariableOrigin {}; - let vid = self - .inner - .borrow_mut() - .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe }) - .vid; + pub fn next_const_var_in_universe(&self, universe: UniverseIndex, span: Span) -> Const<'db> { + let vid = self.next_const_vid_in_universe(universe, span); Const::new_var(self.interner, vid) } pub fn next_int_var(&self) -> Ty<'db> { - let next_int_var_id = - self.inner.borrow_mut().int_unification_table().new_key(IntVarValue::Unknown); - Ty::new_int_var(self.interner, next_int_var_id) + let vid = self.next_int_vid(); + Ty::new_int_var(self.interner, vid) } pub fn next_int_vid(&self) -> IntVid { @@ -828,27 +805,27 @@ impl<'db> InferCtxt<'db> { /// Creates a fresh region variable with the next available index. /// The variable will be created in the maximum universe created /// thus far, allowing it to name any region created thus far. - pub fn next_region_var(&self) -> Region<'db> { - self.next_region_var_in_universe(self.universe()) + pub fn next_region_var(&self, span: Span) -> Region<'db> { + self.next_region_var_in_universe(self.universe(), span) } - pub fn next_region_vid(&self) -> RegionVid { - self.inner.borrow_mut().unwrap_region_constraints().new_region_var(self.universe()) + pub fn next_region_vid(&self, span: Span) -> RegionVid { + self.inner.borrow_mut().unwrap_region_constraints().new_region_var(self.universe(), span) } /// Creates a fresh region variable with the next available index /// in the given universe; typically, you can use /// `next_region_var` and just use the maximal universe. - pub fn next_region_var_in_universe(&self, universe: UniverseIndex) -> Region<'db> { + pub fn next_region_var_in_universe(&self, universe: UniverseIndex, span: Span) -> Region<'db> { let region_var = - self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe); + self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe, span); Region::new_var(self.interner, region_var) } - pub fn next_term_var_of_kind(&self, term: Term<'db>) -> Term<'db> { + pub fn next_term_var_of_kind(&self, term: Term<'db>, span: Span) -> Term<'db> { match term.kind() { - TermKind::Ty(_) => self.next_ty_var().into(), - TermKind::Const(_) => self.next_const_var().into(), + TermKind::Ty(_) => self.next_ty_var(span).into(), + TermKind::Const(_) => self.next_const_var(span).into(), } } @@ -866,24 +843,12 @@ impl<'db> InferCtxt<'db> { self.inner.borrow_mut().unwrap_region_constraints().num_region_vars() } - /// Just a convenient wrapper of `next_region_var` for using during NLL. - #[instrument(skip(self), level = "debug")] - pub fn next_nll_region_var(&self) -> Region<'db> { - self.next_region_var() - } - - /// Just a convenient wrapper of `next_region_var` for using during NLL. - #[instrument(skip(self), level = "debug")] - pub fn next_nll_region_var_in_universe(&self, universe: UniverseIndex) -> Region<'db> { - self.next_region_var_in_universe(universe) - } - - fn var_for_def(&self, id: GenericParamId) -> GenericArg<'db> { + pub fn var_for_def(&self, id: GenericParamId, span: Span) -> GenericArg<'db> { match id { GenericParamId::LifetimeParamId(_) => { // Create a region inference variable for the given // region parameter definition. - self.next_region_var().into() + self.next_region_var(span).into() } GenericParamId::TypeParamId(_) => { // Create a type inference variable for the given @@ -894,41 +859,27 @@ impl<'db> InferCtxt<'db> { // used in a path such as `Foo::<T, U>::new()` will // use an inference variable for `C` with `[T, U]` // as the generic parameters for the default, `(T, U)`. - let ty_var_id = self - .inner - .borrow_mut() - .type_variables() - .new_var(self.universe(), TypeVariableOrigin { param_def_id: None }); - - Ty::new_var(self.interner, ty_var_id).into() - } - GenericParamId::ConstParamId(_) => { - let origin = ConstVariableOrigin {}; - let const_var_id = self - .inner - .borrow_mut() - .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) - .vid; - Const::new_var(self.interner, const_var_id).into() + self.next_ty_var(span).into() } + GenericParamId::ConstParamId(_) => self.next_const_var(span).into(), } } /// Given a set of generics defined on a type or impl, returns the generic parameters mapping /// each type/region parameter to a fresh inference variable. - pub fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> { - GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind)) + pub fn fresh_args_for_item(&self, span: Span, def_id: SolverDefId) -> GenericArgs<'db> { + GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind, span)) } /// Like `fresh_args_for_item()`, but first uses the args from `first`. pub fn fill_rest_fresh_args( &self, + span: Span, def_id: SolverDefId, first: impl IntoIterator<Item = GenericArg<'db>>, ) -> GenericArgs<'db> { GenericArgs::fill_rest(self.interner, def_id, first, |_index, kind, _| { - self.var_for_def(kind) + self.var_for_def(kind, span) }) } @@ -995,8 +946,8 @@ impl<'db> InferCtxt<'db> { use self::type_variable::TypeVariableValue; match self.inner.borrow_mut().type_variables().probe(vid) { - TypeVariableValue::Known { value } => Ok(value), - TypeVariableValue::Unknown { universe } => Err(universe), + TypeVariableValue::Known { value, .. } => Ok(value), + TypeVariableValue::Unknown { universe, .. } => Err(universe), } } @@ -1064,6 +1015,13 @@ impl<'db> InferCtxt<'db> { } } + pub fn shallow_resolve_term(&self, term: Term<'db>) -> Term<'db> { + match term.kind() { + TermKind::Ty(ty) => self.shallow_resolve(ty).into(), + TermKind::Const(ct) => self.shallow_resolve_const(ct).into(), + } + } + pub fn root_var(&self, var: TyVid) -> TyVid { self.inner.borrow_mut().type_variables().root_var(var) } @@ -1141,7 +1099,22 @@ impl<'db> InferCtxt<'db> { pub fn probe_const_var(&self, vid: ConstVid) -> Result<Const<'db>, UniverseIndex> { match self.inner.borrow_mut().const_unification_table().probe_value(vid) { ConstVariableValue::Known { value } => Ok(value), - ConstVariableValue::Unknown { origin: _, universe } => Err(universe), + ConstVariableValue::Unknown { span: _, universe } => Err(universe), + } + } + + /// Returns the span of the type variable identified by `vid`. + /// + /// No attempt is made to resolve `vid` to its root variable. + pub fn type_var_span(&self, vid: TyVid) -> Span { + self.inner.borrow_mut().type_variables().var_span(vid) + } + + /// Returns the span of the const variable identified by `vid` + pub fn const_var_span(&self, vid: ConstVid) -> Option<Span> { + match self.inner.borrow_mut().const_unification_table().probe_value(vid) { + ConstVariableValue::Known { .. } => None, + ConstVariableValue::Unknown { span, .. } => Some(span), } } @@ -1154,6 +1127,7 @@ impl<'db> InferCtxt<'db> { // use [`InferCtxt::enter_forall`] instead. pub fn instantiate_binder_with_fresh_vars<T>( &self, + span: Span, _lbrct: BoundRegionConversionTime, value: Binder<'db, T>, ) -> T @@ -1169,9 +1143,9 @@ impl<'db> InferCtxt<'db> { for bound_var_kind in bound_vars { let arg: GenericArg<'db> = match bound_var_kind { - BoundVariableKind::Ty(_) => self.next_ty_var().into(), - BoundVariableKind::Region(_) => self.next_region_var().into(), - BoundVariableKind::Const => self.next_const_var().into(), + BoundVariableKind::Ty(_) => self.next_ty_var(span).into(), + BoundVariableKind::Region(_) => self.next_region_var(span).into(), + BoundVariableKind::Const => self.next_const_var(span).into(), }; args.push(arg); } diff --git a/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs b/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs index 7bb39519f5..544d79daf0 100644 --- a/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs +++ b/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs @@ -15,9 +15,12 @@ use self::CombineMapType::*; use self::UndoLog::*; use super::MemberConstraint; use super::unify_key::RegionVidKey; -use crate::next_solver::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot}; use crate::next_solver::infer::unify_key::RegionVariableValue; use crate::next_solver::{AliasTy, Binder, DbInterner, ParamTy, PlaceholderType, Region, Ty}; +use crate::{ + Span, + next_solver::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot}, +}; #[derive(Debug, Clone, Default)] pub struct RegionConstraintStorage<'db> { @@ -281,6 +284,7 @@ pub struct RegionVariableInfo { // This would be currently unsound as it would cause us to drop the universe // changes in `lexical_region_resolve`. pub universe: UniverseIndex, + pub span: Span, } pub(crate) struct RegionSnapshot { @@ -350,8 +354,12 @@ impl<'db> RegionConstraintCollector<'db, '_> { *any_unifications = false; // Manually inlined `self.unification_table_mut()` as `self` is used in the closure. ut::UnificationTable::with_log(&mut self.storage.unification_table, &mut self.undo_log) - .reset_unifications(|key| RegionVariableValue::Unknown { - universe: self.storage.var_infos[key.vid].universe, + .reset_unifications(|key| { + let var_info = &self.storage.var_infos[key.vid]; + RegionVariableValue::Unknown { + universe: var_info.universe, + span: var_info.span, + } }); } @@ -372,10 +380,11 @@ impl<'db> RegionConstraintCollector<'db, '_> { self.storage.any_unifications = snapshot.any_unifications; } - pub(super) fn new_region_var(&mut self, universe: UniverseIndex) -> RegionVid { - let vid = self.storage.var_infos.push(RegionVariableInfo { universe }); + pub(super) fn new_region_var(&mut self, universe: UniverseIndex, span: Span) -> RegionVid { + let vid = self.storage.var_infos.push(RegionVariableInfo { universe, span }); - let u_vid = self.unification_table_mut().new_key(RegionVariableValue::Unknown { universe }); + let u_vid = + self.unification_table_mut().new_key(RegionVariableValue::Unknown { universe, span }); assert_eq!(vid, u_vid.vid); self.undo_log.push(AddVar(vid)); debug!("created new region variable {:?} in {:?}", vid, universe); @@ -409,7 +418,7 @@ impl<'db> RegionConstraintCollector<'db, '_> { debug!("make_eqregion: unifying {:?} with {:?}", vid, b); if self .unification_table_mut() - .unify_var_value(vid, RegionVariableValue::Known { value: b }) + .unify_var_value(vid, RegionVariableValue::Known { value: b, span: None }) .is_ok() { self.storage.any_unifications = true; @@ -419,7 +428,7 @@ impl<'db> RegionConstraintCollector<'db, '_> { debug!("make_eqregion: unifying {:?} with {:?}", a, vid); if self .unification_table_mut() - .unify_var_value(vid, RegionVariableValue::Known { value: a }) + .unify_var_value(vid, RegionVariableValue::Known { value: a, span: None }) .is_ok() { self.storage.any_unifications = true; @@ -459,6 +468,7 @@ impl<'db> RegionConstraintCollector<'db, '_> { pub(super) fn lub_regions( &mut self, db: DbInterner<'db>, + origin: Span, a: Region<'db>, b: Region<'db>, ) -> Region<'db> { @@ -470,13 +480,14 @@ impl<'db> RegionConstraintCollector<'db, '_> { } else if a == b { a // LUB(a,a) = a } else { - self.combine_vars(db, Lub, a, b) + self.combine_vars(db, Lub, a, b, origin) } } pub(super) fn glb_regions( &mut self, db: DbInterner<'db>, + origin: Span, a: Region<'db>, b: Region<'db>, ) -> Region<'db> { @@ -490,7 +501,7 @@ impl<'db> RegionConstraintCollector<'db, '_> { } else if a == b { a // GLB(a,a) = a } else { - self.combine_vars(db, Glb, a, b) + self.combine_vars(db, Glb, a, b, origin) } } @@ -504,15 +515,15 @@ impl<'db> RegionConstraintCollector<'db, '_> { let mut ut = self.unification_table_mut(); let root_vid = ut.find(vid).vid; match ut.probe_value(root_vid) { - RegionVariableValue::Known { value } => value, + RegionVariableValue::Known { value, .. } => value, RegionVariableValue::Unknown { .. } => Region::new_var(cx, root_vid), } } pub fn probe_value(&mut self, vid: RegionVid) -> Result<Region<'db>, UniverseIndex> { match self.unification_table_mut().probe_value(vid) { - RegionVariableValue::Known { value } => Ok(value), - RegionVariableValue::Unknown { universe } => Err(universe), + RegionVariableValue::Known { value, .. } => Ok(value), + RegionVariableValue::Unknown { universe, .. } => Err(universe), } } @@ -529,6 +540,7 @@ impl<'db> RegionConstraintCollector<'db, '_> { t: CombineMapType, a: Region<'db>, b: Region<'db>, + origin: Span, ) -> Region<'db> { let vars = TwoRegions { a, b }; if let Some(c) = self.combine_map(t.clone()).get(&vars) { @@ -537,7 +549,7 @@ impl<'db> RegionConstraintCollector<'db, '_> { let a_universe = self.universe(a); let b_universe = self.universe(b); let c_universe = cmp::max(a_universe, b_universe); - let c = self.new_region_var(c_universe); + let c = self.new_region_var(c_universe, origin); self.combine_map(t.clone()).insert(vars.clone(), c); self.undo_log.push(AddCombination(t.clone(), vars)); let new_r = Region::new_var(cx, c); @@ -567,8 +579,15 @@ impl<'db> RegionConstraintCollector<'db, '_> { } } - pub fn vars_since_snapshot(&self, value_count: usize) -> Range<RegionVid> { - RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len()) + pub fn vars_since_snapshot(&self, value_count: usize) -> (Range<RegionVid>, Vec<Span>) { + let range = + RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len()); + ( + range.clone(), + (range.start.as_usize()..range.end.as_usize()) + .map(|index| self.storage.var_infos[RegionVid::from_usize(index)].span) + .collect(), + ) } /// See `InferCtxt::region_constraints_added_in_snapshot`. diff --git a/crates/hir-ty/src/next_solver/infer/relate/generalize.rs b/crates/hir-ty/src/next_solver/infer/relate/generalize.rs index d621dd4906..e55e43a4cd 100644 --- a/crates/hir-ty/src/next_solver/infer/relate/generalize.rs +++ b/crates/hir-ty/src/next_solver/infer/relate/generalize.rs @@ -16,7 +16,6 @@ use tracing::{debug, instrument, warn}; use super::{ PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation, }; -use crate::next_solver::infer::unify_key::ConstVariableValue; use crate::next_solver::infer::{InferCtxt, relate}; use crate::next_solver::util::MaxUniverse; use crate::next_solver::{ @@ -24,6 +23,7 @@ use crate::next_solver::{ Term, TermVid, Ty, TyKind, TypingMode, UnevaluatedConst, }; use crate::next_solver::{GenericArgs, infer::type_variable::TypeVariableValue}; +use crate::{Span, next_solver::infer::unify_key::ConstVariableValue}; impl<'db> InferCtxt<'db> { /// The idea is that we should ensure that the type variable `target_vid` @@ -60,6 +60,7 @@ impl<'db> InferCtxt<'db> { // `?1 <: ?3`. let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self .generalize( + relation.span(), relation.structurally_relate_aliases(), target_vid, instantiation_variance, @@ -179,6 +180,7 @@ impl<'db> InferCtxt<'db> { // constants and generic expressions are not yet handled correctly. let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = self .generalize( + relation.span(), relation.structurally_relate_aliases(), target_vid, Variance::Invariant, @@ -220,6 +222,7 @@ impl<'db> InferCtxt<'db> { /// This checks for cycles -- that is, whether `source_term` references `target_vid`. fn generalize<T: Into<Term<'db>> + Relate<DbInterner<'db>>>( &self, + span: Span, structurally_relate_aliases: StructurallyRelateAliases, target_vid: impl Into<TermVid>, ambient_variance: Variance, @@ -238,6 +241,7 @@ impl<'db> InferCtxt<'db> { let mut generalizer = Generalizer { infcx: self, + span, structurally_relate_aliases, root_vid, for_universe, @@ -270,6 +274,8 @@ impl<'db> InferCtxt<'db> { struct Generalizer<'me, 'db> { infcx: &'me InferCtxt<'db>, + span: Span, + /// Whether aliases should be related structurally. If not, we have to /// be careful when generalizing aliases. structurally_relate_aliases: StructurallyRelateAliases, @@ -318,7 +324,7 @@ impl<'db> Generalizer<'_, 'db> { /// if we're currently in a bivariant context. fn next_ty_var_for_alias(&mut self) -> Ty<'db> { self.has_unconstrained_ty_var |= self.ambient_variance == Variance::Bivariant; - self.infcx.next_ty_var_in_universe(self.for_universe) + self.infcx.next_ty_var_in_universe(self.for_universe, self.span) } /// An occurs check failure inside of an alias does not mean @@ -453,11 +459,11 @@ impl<'db> TypeRelation<DbInterner<'db>> for Generalizer<'_, 'db> { } else { let probe = inner.type_variables().probe(vid); match probe { - TypeVariableValue::Known { value: u } => { + TypeVariableValue::Known { value: u, .. } => { drop(inner); self.relate(u, u) } - TypeVariableValue::Unknown { universe } => { + TypeVariableValue::Unknown { universe, .. } => { match self.ambient_variance { // Invariant: no need to make a fresh type variable // if we can name the universe. @@ -477,7 +483,7 @@ impl<'db> TypeRelation<DbInterner<'db>> for Generalizer<'_, 'db> { Variance::Covariant | Variance::Contravariant => (), } - let origin = inner.type_variables().var_origin(vid); + let origin = inner.type_variables().var_span(vid); let new_var_id = inner.type_variables().new_var(self.for_universe, origin); // If we're in the new solver and create a new inference @@ -579,7 +585,7 @@ impl<'db> TypeRelation<DbInterner<'db>> for Generalizer<'_, 'db> { } } - Ok(self.infcx.next_region_var_in_universe(self.for_universe)) + Ok(self.infcx.next_region_var_in_universe(self.for_universe, self.span)) } #[instrument(level = "debug", skip(self, c2), ret)] @@ -605,13 +611,13 @@ impl<'db> TypeRelation<DbInterner<'db>> for Generalizer<'_, 'db> { drop(inner); self.relate(u, u) } - ConstVariableValue::Unknown { origin, universe } => { + ConstVariableValue::Unknown { span, universe } => { if self.for_universe.can_name(universe) { Ok(c) } else { let new_var_id = variable_table .new_key(ConstVariableValue::Unknown { - origin, + span, universe: self.for_universe, }) .vid; diff --git a/crates/hir-ty/src/next_solver/infer/relate/lattice.rs b/crates/hir-ty/src/next_solver/infer/relate/lattice.rs index 3522827a9e..0443dbd814 100644 --- a/crates/hir-ty/src/next_solver/infer/relate/lattice.rs +++ b/crates/hir-ty/src/next_solver/infer/relate/lattice.rs @@ -19,7 +19,7 @@ use rustc_type_ir::{ AliasRelationDirection, Interner, TypeVisitableExt, Upcast, Variance, - inherent::{IntoKind, Span as _}, + inherent::IntoKind, relate::{ Relate, StructurallyRelateAliases, TypeRelation, VarianceDiagInfo, combine::{ @@ -28,13 +28,16 @@ use rustc_type_ir::{ }, }; -use crate::next_solver::{ - AliasTy, Binder, Const, DbInterner, GenericArgs, Goal, ParamEnv, Predicate, PredicateKind, - Region, SolverDefId, Span, Ty, TyKind, - infer::{ - InferCtxt, TypeTrace, - relate::RelateResult, - traits::{Obligation, PredicateObligations}, +use crate::{ + Span, + next_solver::{ + AliasTy, Binder, Const, DbInterner, GenericArgs, Goal, ParamEnv, Predicate, PredicateKind, + Region, SolverDefId, Ty, TyKind, + infer::{ + InferCtxt, TypeTrace, + relate::RelateResult, + traits::{Obligation, PredicateObligations}, + }, }, }; @@ -154,12 +157,12 @@ impl<'db> TypeRelation<DbInterner<'db>> for LatticeOp<'_, 'db> { // iterate on the subtype obligations that are returned, but I // think this suffices. -nmatsakis (TyKind::Infer(rustc_type_ir::TyVar(..)), _) => { - let v = infcx.next_ty_var(); + let v = infcx.next_ty_var(self.span()); self.relate_bound(v, b, a)?; Ok(v) } (_, TyKind::Infer(rustc_type_ir::TyVar(..))) => { - let v = infcx.next_ty_var(); + let v = infcx.next_ty_var(self.span()); self.relate_bound(v, a, b)?; Ok(v) } @@ -178,10 +181,10 @@ impl<'db> TypeRelation<DbInterner<'db>> for LatticeOp<'_, 'db> { let mut constraints = inner.unwrap_region_constraints(); Ok(match self.kind { // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 - LatticeOpKind::Glb => constraints.lub_regions(self.cx(), a, b), + LatticeOpKind::Glb => constraints.lub_regions(self.cx(), self.span(), a, b), // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8 - LatticeOpKind::Lub => constraints.glb_regions(self.cx(), a, b), + LatticeOpKind::Lub => constraints.glb_regions(self.cx(), self.span(), a, b), }) } @@ -239,7 +242,7 @@ impl<'infcx, 'db> LatticeOp<'infcx, 'db> { impl<'db> PredicateEmittingRelation<InferCtxt<'db>> for LatticeOp<'_, 'db> { fn span(&self) -> Span { - Span::dummy() + self.trace.cause.span() } fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { diff --git a/crates/hir-ty/src/next_solver/infer/select.rs b/crates/hir-ty/src/next_solver/infer/select.rs index bbfc8a4757..d6f0379c11 100644 --- a/crates/hir-ty/src/next_solver/infer/select.rs +++ b/crates/hir-ty/src/next_solver/infer/select.rs @@ -10,6 +10,7 @@ use rustc_type_ir::{ }; use crate::{ + Span, db::InternedOpaqueTyId, next_solver::{ AnyImplId, Const, ErrorGuaranteed, GenericArgs, Goal, TraitRef, Ty, TypeError, @@ -263,18 +264,24 @@ impl<'db> InferCtxt<'db> { ) -> SelectionResult<'db, Selection<'db>> { self.visit_proof_tree( Goal::new(self.interner, obligation.param_env, obligation.predicate), - &mut Select {}, + &mut Select { span: obligation.cause.span() }, ) .break_value() .unwrap() } } -struct Select {} +struct Select { + span: Span, +} impl<'db> ProofTreeVisitor<'db> for Select { type Result = ControlFlow<SelectionResult<'db, Selection<'db>>>; + fn span(&self) -> Span { + self.span + } + fn visit_goal(&mut self, goal: &InspectGoal<'_, 'db>) -> Self::Result { let mut candidates = goal.candidates(); candidates.retain(|cand| cand.result().is_ok()); @@ -286,7 +293,10 @@ impl<'db> ProofTreeVisitor<'db> for Select { // One candidate, no need to winnow. if candidates.len() == 1 { - return ControlFlow::Break(Ok(to_selection(candidates.into_iter().next().unwrap()))); + return ControlFlow::Break(Ok(to_selection( + self.span, + candidates.into_iter().next().unwrap(), + ))); } // Don't winnow until `Certainty::Yes` -- we don't need to winnow until @@ -311,7 +321,7 @@ impl<'db> ProofTreeVisitor<'db> for Select { } } - ControlFlow::Break(Ok(to_selection(candidates.into_iter().next().unwrap()))) + ControlFlow::Break(Ok(to_selection(self.span, candidates.into_iter().next().unwrap()))) } } @@ -368,7 +378,7 @@ fn candidate_should_be_dropped_in_favor_of<'db>( } } -fn to_selection<'db>(cand: InspectCandidate<'_, 'db>) -> Option<Selection<'db>> { +fn to_selection<'db>(span: Span, cand: InspectCandidate<'_, 'db>) -> Option<Selection<'db>> { if let Certainty::Maybe { .. } = cand.shallow_certainty() { return None; } @@ -376,7 +386,7 @@ fn to_selection<'db>(cand: InspectCandidate<'_, 'db>) -> Option<Selection<'db>> let nested = match cand.result().expect("expected positive result") { Certainty::Yes => Vec::new(), Certainty::Maybe { .. } => cand - .instantiate_nested_goals() + .instantiate_nested_goals(span) .into_iter() .map(|nested| { Obligation::new( @@ -396,7 +406,7 @@ fn to_selection<'db>(cand: InspectCandidate<'_, 'db>) -> Option<Selection<'db>> // For impl candidates, we do the rematch manually to compute the args. ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, - args: cand.instantiate_impl_args(), + args: cand.instantiate_impl_args(span), nested, }) } diff --git a/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs b/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs index 5902f8043b..7cb3ab09d4 100644 --- a/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs +++ b/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs @@ -5,17 +5,19 @@ use ena::{ unify::{self as ut, UnifyKey}, }; use rustc_type_ir::{ - ConstVid, FloatVid, IntVid, RegionKind, RegionVid, TyVid, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitableExt, inherent::IntoKind, + ConstVid, FloatVid, IntVid, RegionVid, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, inherent::IntoKind, }; -use crate::next_solver::{ - Const, ConstKind, DbInterner, Region, Ty, TyKind, - infer::{ - InferCtxt, UnificationTable, iter_idx_range, - snapshot::VariableLengths, - type_variable::TypeVariableOrigin, - unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}, +use crate::{ + Span, + next_solver::{ + Const, ConstKind, DbInterner, Region, RegionKind, Ty, TyKind, + infer::{ + InferCtxt, UnificationTable, iter_idx_range, + snapshot::VariableLengths, + unify_key::{ConstVariableValue, ConstVidKey}, + }, }, }; @@ -33,7 +35,7 @@ where fn const_vars_since_snapshot<'db>( table: &mut UnificationTable<'_, 'db, ConstVidKey<'db>>, snapshot_var_len: usize, -) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) { +) -> (Range<ConstVid>, Vec<Span>) { let range = vars_since_snapshot(table, snapshot_var_len); let range = range.start.vid..range.end.vid; @@ -41,8 +43,8 @@ fn const_vars_since_snapshot<'db>( range.clone(), iter_idx_range(range) .map(|index| match table.probe_value(index) { - ConstVariableValue::Known { value: _ } => ConstVariableOrigin {}, - ConstVariableValue::Unknown { origin, universe: _ } => origin, + ConstVariableValue::Known { value: _ } => Span::Dummy, + ConstVariableValue::Unknown { span, universe: _ } => span, }) .collect(), ) @@ -128,11 +130,11 @@ impl<'db> InferCtxt<'db> { } struct SnapshotVarData { - region_vars: Range<RegionVid>, - type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>), + region_vars: (Range<RegionVid>, Vec<Span>), + type_vars: (Range<TyVid>, Vec<Span>), int_vars: Range<IntVid>, float_vars: Range<FloatVid>, - const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>), + const_vars: (Range<ConstVid>, Vec<Span>), } impl SnapshotVarData { @@ -156,7 +158,7 @@ impl SnapshotVarData { fn is_empty(&self) -> bool { let SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars } = self; - region_vars.is_empty() + region_vars.0.is_empty() && type_vars.0.is_empty() && int_vars.is_empty() && float_vars.is_empty() @@ -182,8 +184,8 @@ impl<'a, 'db> TypeFolder<DbInterner<'db>> for InferenceFudger<'a, 'db> { // This variable was created during the fudging. // Recreate it with a fresh variable here. let idx = vid.as_usize() - self.snapshot_vars.type_vars.0.start.as_usize(); - let origin = self.snapshot_vars.type_vars.1[idx]; - self.infcx.next_ty_var_with_origin(origin) + let span = self.snapshot_vars.type_vars.1[idx]; + self.infcx.next_ty_var(span) } else { // This variable was created before the // "fudging". Since we refresh all type @@ -225,8 +227,10 @@ impl<'a, 'db> TypeFolder<DbInterner<'db>> for InferenceFudger<'a, 'db> { fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { if let RegionKind::ReVar(vid) = r.kind() { - if self.snapshot_vars.region_vars.contains(&vid) { - self.infcx.next_region_var() + if self.snapshot_vars.region_vars.0.contains(&vid) { + let idx = vid.index() - self.snapshot_vars.region_vars.0.start.index(); + let span = self.snapshot_vars.region_vars.1[idx]; + self.infcx.next_region_var(span) } else { r } @@ -241,8 +245,8 @@ impl<'a, 'db> TypeFolder<DbInterner<'db>> for InferenceFudger<'a, 'db> { rustc_type_ir::InferConst::Var(vid) => { if self.snapshot_vars.const_vars.0.contains(&vid) { let idx = vid.index() - self.snapshot_vars.const_vars.0.start.index(); - let origin = self.snapshot_vars.const_vars.1[idx]; - self.infcx.next_const_var_with_origin(origin) + let span = self.snapshot_vars.const_vars.1[idx]; + self.infcx.next_const_var(span) } else { ct } diff --git a/crates/hir-ty/src/next_solver/infer/traits.rs b/crates/hir-ty/src/next_solver/infer/traits.rs index 5b875d2960..1edf256d01 100644 --- a/crates/hir-ty/src/next_solver/infer/traits.rs +++ b/crates/hir-ty/src/next_solver/infer/traits.rs @@ -16,9 +16,12 @@ use rustc_type_ir::{ }; use tracing::debug; -use crate::next_solver::{ - Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, Span, TraitPredicate, - TraitRef, Ty, +use crate::{ + Span, + next_solver::{ + Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, TraitPredicate, + TraitRef, Ty, + }, }; use super::InferCtxt; @@ -33,15 +36,18 @@ use super::InferCtxt; /// only live for a short period of time. #[derive(Clone, Debug, PartialEq, Eq)] pub struct ObligationCause { - // FIXME: This should contain an `ExprId`/`PatId` etc., and a cause code. But for now we - // don't report trait solving diagnostics, so this is irrelevant. - _private: (), + span: Span, } impl ObligationCause { #[inline] pub fn new() -> ObligationCause { - ObligationCause { _private: () } + ObligationCause { span: Span::Dummy } + } + + #[inline] + pub fn with_span(span: Span) -> ObligationCause { + ObligationCause { span } } #[inline] @@ -53,6 +59,11 @@ impl ObligationCause { pub fn misc() -> ObligationCause { ObligationCause::new() } + + #[inline] + pub(crate) fn span(&self) -> Span { + self.span + } } impl Default for ObligationCause { diff --git a/crates/hir-ty/src/next_solver/infer/type_variable.rs b/crates/hir-ty/src/next_solver/infer/type_variable.rs index 29e7b883c9..6b3936ba80 100644 --- a/crates/hir-ty/src/next_solver/infer/type_variable.rs +++ b/crates/hir-ty/src/next_solver/infer/type_variable.rs @@ -7,13 +7,12 @@ use std::ops::Range; use ena::snapshot_vec as sv; use ena::undo_log::Rollback; use ena::unify as ut; -use rustc_index::IndexVec; use rustc_type_ir::TyVid; use rustc_type_ir::UniverseIndex; use rustc_type_ir::inherent::Ty as _; use tracing::debug; -use crate::next_solver::SolverDefId; +use crate::Span; use crate::next_solver::Ty; use crate::next_solver::infer::{InferCtxtUndoLogs, iter_idx_range}; @@ -61,8 +60,6 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for TypeVariableStorage<'tcx> { #[derive(Debug, Clone, Default)] pub(crate) struct TypeVariableStorage<'db> { - /// The origins of each type variable. - values: IndexVec<TyVid, TypeVariableData>, /// Two variables are unified in `eq_relations` when we have a /// constraint `?X == ?Y`. This table also stores, for each key, /// the known value. @@ -94,20 +91,7 @@ pub(crate) struct TypeVariableTable<'a, 'db> { undo_log: &'a mut InferCtxtUndoLogs<'db>, } -#[derive(Copy, Clone, Debug)] -pub struct TypeVariableOrigin { - /// `DefId` of the type parameter this was instantiated for, if any. - /// - /// This should only be used for diagnostics. - pub param_def_id: Option<SolverDefId>, -} - -#[derive(Debug, Clone)] -pub(crate) struct TypeVariableData { - origin: TypeVariableOrigin, -} - -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub(crate) enum TypeVariableValue<'db> { Known { value: Ty<'db> }, Unknown { universe: UniverseIndex }, @@ -119,7 +103,7 @@ impl<'db> TypeVariableValue<'db> { pub(crate) fn known(&self) -> Option<Ty<'db>> { match self { TypeVariableValue::Unknown { .. } => None, - TypeVariableValue::Known { value } => Some(*value), + TypeVariableValue::Known { value, .. } => Some(*value), } } @@ -145,19 +129,14 @@ impl<'db> TypeVariableStorage<'db> { &self.eq_relations } - pub(super) fn finalize_rollback(&mut self) { - debug_assert!(self.values.len() >= self.eq_relations.len()); - self.values.truncate(self.eq_relations.len()); - } + pub(super) fn finalize_rollback(&mut self) {} } impl<'db> TypeVariableTable<'_, 'db> { - /// Returns the origin that was given when `vid` was created. - /// - /// Note that this function does not return care whether - /// `vid` has been unified with something else or not. - pub(crate) fn var_origin(&self, vid: TyVid) -> TypeVariableOrigin { - self.storage.values[vid].origin + pub(crate) fn var_span(&mut self, vid: TyVid) -> Span { + // We return the span from unification and not equation, since when equating we also unify, + // and we want to prevent duplicate diagnostics from vars that were unified. + self.sub_unification_table().probe_value(vid).span } /// Records that `a == b`, depending on `dir`. @@ -195,33 +174,20 @@ impl<'db> TypeVariableTable<'_, 'db> { self.eq_relations().union_value(vid, TypeVariableValue::Known { value: ty }); } - /// Creates a new type variable. - /// - /// - `diverging`: indicates if this is a "diverging" type - /// variable, e.g., one created as the type of a `return` - /// expression. The code in this module doesn't care if a - /// variable is diverging, but the main Rust type-checker will - /// sometimes "unify" such variables with the `!` or `()` types. - /// - `origin`: indicates *why* the type variable was created. - /// The code in this module doesn't care, but it can be useful - /// for improving error messages. - pub(crate) fn new_var(&mut self, universe: UniverseIndex, origin: TypeVariableOrigin) -> TyVid { + pub(crate) fn new_var(&mut self, universe: UniverseIndex, span: Span) -> TyVid { let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); - let sub_key = self.sub_unification_table().new_key(()); + let sub_key = self.sub_unification_table().new_key(TypeVariableSubValue { span }); debug_assert_eq!(eq_key.vid, sub_key.vid); - let index = self.storage.values.push(TypeVariableData { origin }); - debug_assert_eq!(eq_key.vid, index); - - debug!("new_var(index={:?}, universe={:?}, origin={:?})", eq_key.vid, universe, origin); + debug!("new_var(index={:?}, universe={:?}, span={:?})", eq_key.vid, universe, span); - index + eq_key.vid } /// Returns the number of type variables created thus far. pub(crate) fn num_vars(&self) -> usize { - self.storage.values.len() + self.storage.eq_relations.len() } /// Returns the "root" variable of `vid` in the `eq_relations` @@ -268,12 +234,9 @@ impl<'db> TypeVariableTable<'_, 'db> { } /// Returns a range of the type variables created during the snapshot. - pub(crate) fn vars_since_snapshot( - &mut self, - value_count: usize, - ) -> (Range<TyVid>, Vec<TypeVariableOrigin>) { + pub(crate) fn vars_since_snapshot(&mut self, value_count: usize) -> (Range<TyVid>, Vec<Span>) { let range = TyVid::from_usize(value_count)..TyVid::from_usize(self.num_vars()); - (range.clone(), iter_idx_range(range).map(|index| self.var_origin(index)).collect()) + (range.clone(), iter_idx_range(range).map(|index| self.var_span(index)).collect()) } /// Returns indices of all variables that are not yet @@ -324,9 +287,6 @@ impl<'db> ut::UnifyKey for TyVidEqKey<'db> { fn tag() -> &'static str { "TyVidEqKey" } - fn order_roots(a: Self, _: &Self::Value, b: Self, _: &Self::Value) -> Option<(Self, Self)> { - if a.vid.as_u32() < b.vid.as_u32() { Some((a, b)) } else { Some((b, a)) } - } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -341,8 +301,13 @@ impl From<TyVid> for TyVidSubKey { } } +#[derive(Debug, Clone, Copy)] +pub(crate) struct TypeVariableSubValue { + span: Span, +} + impl ut::UnifyKey for TyVidSubKey { - type Value = (); + type Value = TypeVariableSubValue; #[inline] fn index(&self) -> u32 { self.vid.as_u32() @@ -356,6 +321,14 @@ impl ut::UnifyKey for TyVidSubKey { } } +impl ut::UnifyValue for TypeVariableSubValue { + type Error = ut::NoError; + + fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> { + Ok(TypeVariableSubValue { span: Span::pick_best(value1.span, value2.span) }) + } +} + impl<'db> ut::UnifyValue for TypeVariableValue<'db> { type Error = ut::NoError; @@ -369,11 +342,9 @@ impl<'db> ut::UnifyValue for TypeVariableValue<'db> { } // If one side is known, prefer that one. - (&TypeVariableValue::Known { .. }, &TypeVariableValue::Unknown { .. }) => { - Ok(value1.clone()) - } - (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { .. }) => { - Ok(value2.clone()) + (&TypeVariableValue::Known { value }, &TypeVariableValue::Unknown { .. }) + | (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { value }) => { + Ok(TypeVariableValue::Known { value }) } // If both sides are *unknown*, it hardly matters, does it? diff --git a/crates/hir-ty/src/next_solver/infer/unify_key.rs b/crates/hir-ty/src/next_solver/infer/unify_key.rs index a09f65f082..061b8531d3 100644 --- a/crates/hir-ty/src/next_solver/infer/unify_key.rs +++ b/crates/hir-ty/src/next_solver/infer/unify_key.rs @@ -6,12 +6,15 @@ use std::marker::PhantomData; use ena::unify::{NoError, UnifyKey, UnifyValue}; use rustc_type_ir::{ConstVid, RegionKind, RegionVid, UniverseIndex, inherent::IntoKind}; -use crate::next_solver::{Const, Region}; +use crate::{ + Span, + next_solver::{Const, Region}, +}; -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub(crate) enum RegionVariableValue<'db> { - Known { value: Region<'db> }, - Unknown { universe: UniverseIndex }, + Known { value: Region<'db>, span: Option<Span> }, + Unknown { universe: UniverseIndex, span: Span }, } #[derive(PartialEq, Copy, Clone, Debug)] @@ -51,9 +54,15 @@ impl<'db> UnifyValue for RegionVariableValue<'db> { Err(RegionUnificationError) } - (RegionVariableValue::Known { value }, RegionVariableValue::Unknown { universe }) - | (RegionVariableValue::Unknown { universe }, RegionVariableValue::Known { value }) => { - let universe_of_value = match (*value).kind() { + ( + &RegionVariableValue::Known { value, span: span_known }, + &RegionVariableValue::Unknown { universe, span: span_unknown }, + ) + | ( + &RegionVariableValue::Unknown { universe, span: span_unknown }, + &RegionVariableValue::Known { value, span: span_known }, + ) => { + let universe_of_value = match value.kind() { RegionKind::ReStatic | RegionKind::ReErased | RegionKind::ReLateParam(..) @@ -65,23 +74,28 @@ impl<'db> UnifyValue for RegionVariableValue<'db> { } }; + let span = match span_known { + Some(span_known) => Span::pick_best(span_known, span_unknown), + None => span_unknown, + }; if universe.can_name(universe_of_value) { - Ok(RegionVariableValue::Known { value: *value }) + Ok(RegionVariableValue::Known { value, span: Some(span) }) } else { Err(RegionUnificationError) } } ( - RegionVariableValue::Unknown { universe: a }, - RegionVariableValue::Unknown { universe: b }, + &RegionVariableValue::Unknown { universe: a, span: span1 }, + &RegionVariableValue::Unknown { universe: b, span: span2 }, ) => { // If we unify two unconstrained regions then whatever // value they wind up taking (which must be the same value) must // be nameable by both universes. Therefore, the resulting // universe is the minimum of the two universes, because that is // the one which contains the fewest names in scope. - Ok(RegionVariableValue::Unknown { universe: (*a).min(*b) }) + let span = Span::pick_best(span1, span2); + Ok(RegionVariableValue::Unknown { universe: a.min(b), span }) } } } @@ -89,13 +103,10 @@ impl<'db> UnifyValue for RegionVariableValue<'db> { // Generic consts. -#[derive(Copy, Clone, Debug)] -pub struct ConstVariableOrigin {} - -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub(crate) enum ConstVariableValue<'db> { Known { value: Const<'db> }, - Unknown { origin: ConstVariableOrigin, universe: UniverseIndex }, + Unknown { span: Span, universe: UniverseIndex }, } impl<'db> ConstVariableValue<'db> { @@ -134,9 +145,6 @@ impl<'db> UnifyKey for ConstVidKey<'db> { fn tag() -> &'static str { "ConstVidKey" } - fn order_roots(a: Self, _: &Self::Value, b: Self, _: &Self::Value) -> Option<(Self, Self)> { - if a.vid.as_u32() < b.vid.as_u32() { Some((a, b)) } else { Some((b, a)) } - } } impl<'db> UnifyValue for ConstVariableValue<'db> { @@ -149,25 +157,22 @@ impl<'db> UnifyValue for ConstVariableValue<'db> { } // If one side is known, prefer that one. - (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => { - Ok(value1.clone()) - } - (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => { - Ok(value2.clone()) - } + (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => Ok(*value1), + (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => Ok(*value2), // If both sides are *unknown*, it hardly matters, does it? ( - ConstVariableValue::Unknown { origin, universe: universe1 }, - ConstVariableValue::Unknown { origin: _, universe: universe2 }, + &ConstVariableValue::Unknown { span: span1, universe: universe1 }, + &ConstVariableValue::Unknown { span: span2, universe: universe2 }, ) => { // If we unify two unbound variables, ?T and ?U, then whatever // value they wind up taking (which must be the same value) must // be nameable by both universes. Therefore, the resulting // universe is the minimum of the two universes, because that is // the one which contains the fewest names in scope. - let universe = cmp::min(*universe1, *universe2); - Ok(ConstVariableValue::Unknown { origin: *origin, universe }) + let universe = cmp::min(universe1, universe2); + let span = Span::pick_best(span1, span2); + Ok(ConstVariableValue::Unknown { span, universe }) } } } diff --git a/crates/hir-ty/src/next_solver/inspect.rs b/crates/hir-ty/src/next_solver/inspect.rs index 63a225b98f..566f72fbd8 100644 --- a/crates/hir-ty/src/next_solver/inspect.rs +++ b/crates/hir-ty/src/next_solver/inspect.rs @@ -6,19 +6,22 @@ use rustc_next_trait_solver::{ }; use rustc_type_ir::{ VisitorResult, - inherent::{IntoKind, Span as _}, + inherent::IntoKind, solve::{Certainty, GoalSource, MaybeCause, NoSolution}, }; -use crate::next_solver::{ - DbInterner, GenericArg, GenericArgs, Goal, NormalizesTo, ParamEnv, Predicate, PredicateKind, - QueryResult, SolverContext, Span, Term, - fulfill::NextSolverError, - infer::{ - InferCtxt, - traits::{Obligation, ObligationCause}, +use crate::{ + Span, + next_solver::{ + DbInterner, GenericArg, GenericArgs, Goal, NormalizesTo, ParamEnv, Predicate, + PredicateKind, QueryResult, SolverContext, Term, + fulfill::NextSolverError, + infer::{ + InferCtxt, + traits::{Obligation, ObligationCause}, + }, + obligation_ctxt::ObligationCtxt, }, - obligation_ctxt::ObligationCtxt, }; pub(crate) struct InspectConfig { @@ -142,7 +145,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { &self, visitor: &mut V, ) -> V::Result { - for goal in self.instantiate_nested_goals() { + for goal in self.instantiate_nested_goals(visitor.span()) { try_visit!(goal.visit_with(visitor)); } @@ -153,7 +156,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { /// inference constraints. This function modifies the state of the `infcx`. /// /// See [`Self::instantiate_impl_args`] if you need the impl args too. - pub(crate) fn instantiate_nested_goals(&self) -> Vec<InspectGoal<'a, 'db>> { + pub(crate) fn instantiate_nested_goals(&self, span: Span) -> Vec<InspectGoal<'a, 'db>> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; let mut orig_values = self.goal.orig_values.to_vec(); @@ -163,13 +166,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { match **step { inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push(( source, - instantiate_canonical_state( - infcx, - Span::dummy(), - param_env, - &mut orig_values, - goal, - ), + instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal), )), inspect::ProbeStep::RecordImplArgs { .. } => {} inspect::ProbeStep::MakeCanonicalResponse { .. } @@ -177,13 +174,8 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { } } - let () = instantiate_canonical_state( - infcx, - Span::dummy(), - param_env, - &mut orig_values, - self.final_state, - ); + let () = + instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state); if let Some(term_hack) = &self.goal.normalizes_to_term_hack { // FIXME: We ignore the expected term of `NormalizesTo` goals @@ -194,14 +186,14 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { instantiated_goals .into_iter() - .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal)) + .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span)) .collect() } /// Instantiate the args of an impl if this candidate came from a /// `CandidateSource::Impl`. This function modifies the state of the /// `infcx`. - pub(crate) fn instantiate_impl_args(&self) -> GenericArgs<'db> { + pub(crate) fn instantiate_impl_args(&self, span: Span) -> GenericArgs<'db> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; let mut orig_values = self.goal.orig_values.to_vec(); @@ -211,7 +203,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { inspect::ProbeStep::RecordImplArgs { impl_args } => { let impl_args = instantiate_canonical_state( infcx, - Span::dummy(), + span, param_env, &mut orig_values, impl_args, @@ -219,7 +211,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { let () = instantiate_canonical_state( infcx, - Span::dummy(), + span, param_env, &mut orig_values, self.final_state, @@ -246,11 +238,12 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { &self, source: GoalSource, goal: Goal<'db, Predicate<'db>>, + span: Span, ) -> InspectGoal<'a, 'db> { let infcx = self.goal.infcx; match goal.predicate.kind().no_bound_vars() { Some(PredicateKind::NormalizesTo(NormalizesTo { alias, term })) => { - let unconstrained_term = infcx.next_term_var_of_kind(term); + let unconstrained_term = infcx.next_term_var_of_kind(term, span); let goal = goal.with(infcx.interner, NormalizesTo { alias, term: unconstrained_term }); // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the @@ -265,8 +258,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { // considering the constrained RHS, and pass the resulting certainty to // `InspectGoal::new` so that the goal has the right result (and maintains // the impression that we don't do this normalizes-to infer hack at all). - let (nested, proof_tree) = - infcx.evaluate_root_goal_for_proof_tree(goal, Span::dummy()); + let (nested, proof_tree) = infcx.evaluate_root_goal_for_proof_tree(goal, span); let nested_goals_result = nested.and_then(|nested| { normalizes_to_term_hack.constrain_and( infcx, @@ -300,7 +292,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { // constraints, we get an ICE if we already applied the constraints // from the chosen candidate. let proof_tree = - infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, Span::dummy()).1); + infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, span).1); InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source) } } @@ -469,6 +461,8 @@ impl<'a, 'db> InspectGoal<'a, 'db> { pub(crate) trait ProofTreeVisitor<'db> { type Result: VisitorResult; + fn span(&self) -> Span; + fn config(&self) -> InspectConfig { InspectConfig { max_depth: 10 } } @@ -496,7 +490,7 @@ impl<'db> InferCtxt<'db> { visitor: &mut V, ) -> V::Result { let (_, proof_tree) = <&SolverContext<'db>>::from(self) - .evaluate_root_goal_for_proof_tree(goal, Span::dummy()); + .evaluate_root_goal_for_proof_tree(goal, visitor.span()); visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc)) } } diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs index 4095dbe47d..af3798f1da 100644 --- a/crates/hir-ty/src/next_solver/interner.rs +++ b/crates/hir-ty/src/next_solver/interner.rs @@ -37,7 +37,7 @@ use rustc_type_ir::{ }; use crate::{ - FnAbi, + FnAbi, Span, db::{HirDatabase, InternedClosure, InternedCoroutineId}, lower::GenericPredicates, method_resolution::TraitImpls, @@ -382,13 +382,9 @@ impl<'db> DbInterner<'db> { } } -// This is intentionally left as `()` -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub struct Span(()); - impl<'db> inherent::Span<DbInterner<'db>> for Span { fn dummy() -> Self { - Span(()) + Span::Dummy } } diff --git a/crates/hir-ty/src/next_solver/normalize.rs b/crates/hir-ty/src/next_solver/normalize.rs index 5d8f3fe519..aa6f27c4c2 100644 --- a/crates/hir-ty/src/next_solver/normalize.rs +++ b/crates/hir-ty/src/next_solver/normalize.rs @@ -99,7 +99,7 @@ impl<'db> NormalizationFolder<'_, 'db> { self.depth += 1; - let infer_term = infcx.next_term_var_of_kind(alias_term); + let infer_term = infcx.next_term_var_of_kind(alias_term, self.at.cause.span()); let obligation = Obligation::new( interner, self.at.cause.clone(), diff --git a/crates/hir-ty/src/next_solver/region.rs b/crates/hir-ty/src/next_solver/region.rs index 3f0aebac2d..7acbcbf4aa 100644 --- a/crates/hir-ty/src/next_solver/region.rs +++ b/crates/hir-ty/src/next_solver/region.rs @@ -136,7 +136,7 @@ impl<'db> Region<'db> { } RegionKind::ReError(..) => { flags |= TypeFlags::HAS_FREE_REGIONS; - flags |= TypeFlags::HAS_ERROR; + flags |= TypeFlags::HAS_RE_ERROR; } } diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs index d45ac6c959..6abc87f088 100644 --- a/crates/hir-ty/src/next_solver/solver.rs +++ b/crates/hir-ty/src/next_solver/solver.rs @@ -6,7 +6,7 @@ use hir_def::{ }; use rustc_next_trait_solver::delegate::SolverDelegate; use rustc_type_ir::{ - AliasTyKind, GenericArgKind, InferCtxtLike, Interner, PredicatePolarity, TypeFlags, + AliasTyKind, GenericArgKind, InferCtxtLike, InferTy, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt, inherent::{IntoKind, Term as _, Ty as _}, lang_items::SolverTraitLangItem, @@ -15,7 +15,7 @@ use rustc_type_ir::{ use tracing::debug; use crate::{ - ParamEnvAndCrate, + ParamEnvAndCrate, Span, next_solver::{ AliasTy, AnyImplId, CanonicalVarKind, Clause, ClauseKind, CoercePredicate, GenericArgs, ParamEnv, Predicate, PredicateKind, SubtypePredicate, Ty, TyKind, UnevaluatedConst, @@ -24,7 +24,7 @@ use crate::{ }; use super::{ - Const, DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span, + Const, DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, infer::{DbInternerInferExt, InferCtxt, canonical::instantiate::CanonicalExt}, }; @@ -63,15 +63,15 @@ impl<'db> SolverDelegate for SolverContext<'db> { where V: rustc_type_ir::TypeFoldable<Self::Interner>, { - let (infcx, value, vars) = cx.infer_ctxt().build_with_canonical(canonical); + let (infcx, value, vars) = cx.infer_ctxt().build_with_canonical(Span::Dummy, canonical); (SolverContext(infcx), value, vars) } - fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, _span: Span) -> GenericArg<'db> { + fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, span: Span) -> GenericArg<'db> { match arg.kind() { - GenericArgKind::Lifetime(_) => self.next_region_var().into(), - GenericArgKind::Type(_) => self.next_ty_var().into(), - GenericArgKind::Const(_) => self.next_const_var().into(), + GenericArgKind::Lifetime(_) => self.next_region_var(span).into(), + GenericArgKind::Type(_) => self.next_ty_var(span).into(), + GenericArgKind::Const(_) => self.next_const_var(span).into(), } } @@ -124,11 +124,11 @@ impl<'db> SolverDelegate for SolverContext<'db> { fn instantiate_canonical_var( &self, kind: CanonicalVarKind<'db>, - _span: <Self::Interner as Interner>::Span, + span: Span, var_values: &[GenericArg<'db>], universe_map: impl Fn(rustc_type_ir::UniverseIndex) -> rustc_type_ir::UniverseIndex, ) -> GenericArg<'db> { - self.0.instantiate_canonical_var(kind, var_values, universe_map) + self.0.instantiate_canonical_var(span, kind, var_values, universe_map) } fn add_item_bounds_for_hidden_type( @@ -293,10 +293,10 @@ impl<'db> SolverDelegate for SolverContext<'db> { } if trait_pred.polarity() == PredicatePolarity::Positive { - match self.0.cx().as_trait_lang_item(trait_pred.def_id()) { + match self.0.interner.as_trait_lang_item(trait_pred.def_id()) { Some(SolverTraitLangItem::Sized) | Some(SolverTraitLangItem::MetaSized) => { let predicate = self.resolve_vars_if_possible(goal.predicate); - if sizedness_fast_path(self.cx(), predicate, goal.param_env) { + if sizedness_fast_path(self.interner, predicate, goal.param_env) { return Some(Certainty::Yes); } } @@ -322,17 +322,31 @@ impl<'db> SolverDelegate for SolverContext<'db> { let pred = goal.predicate.kind(); match pred.no_bound_vars()? { - PredicateKind::Clause(ClauseKind::RegionOutlives(_outlives)) => Some(Certainty::Yes), - PredicateKind::Clause(ClauseKind::TypeOutlives(_outlives)) => Some(Certainty::Yes), + PredicateKind::DynCompatible(def_id) + if self.0.interner.trait_is_dyn_compatible(def_id) => + { + Some(Certainty::Yes) + } + PredicateKind::Clause(ClauseKind::RegionOutlives(outlives)) => { + self.0.sub_regions(outlives.1, outlives.0); + Some(Certainty::Yes) + } + PredicateKind::Clause(ClauseKind::TypeOutlives(outlives)) => { + self.0.register_type_outlives_constraint(outlives.0, outlives.1); + + Some(Certainty::Yes) + } PredicateKind::Subtype(SubtypePredicate { a, b, .. }) | PredicateKind::Coerce(CoercePredicate { a, b }) => { - if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() { - // FIXME: We also need to register a subtype relation between these vars - // when those are added, and if they aren't in the same sub root then - // we should mark this goal as `has_changed`. - Some(Certainty::AMBIGUOUS) - } else { - None + match (self.shallow_resolve(a).kind(), self.shallow_resolve(b).kind()) { + ( + TyKind::Infer(InferTy::TyVar(a_vid)), + TyKind::Infer(InferTy::TyVar(b_vid)), + ) => { + self.sub_unify_ty_vids_raw(a_vid, b_vid); + Some(Certainty::AMBIGUOUS) + } + _ => None, } } PredicateKind::Clause(ClauseKind::ConstArgHasType(ct, _)) => { @@ -343,6 +357,7 @@ impl<'db> SolverDelegate for SolverContext<'db> { } } PredicateKind::Clause(ClauseKind::WellFormed(arg)) => { + let arg = self.shallow_resolve_term(arg); if arg.is_trivially_wf(self.interner) { Some(Certainty::Yes) } else if arg.is_infer() { diff --git a/crates/hir-ty/src/next_solver/structural_normalize.rs b/crates/hir-ty/src/next_solver/structural_normalize.rs index 00c3708358..7a70bae97c 100644 --- a/crates/hir-ty/src/next_solver/structural_normalize.rs +++ b/crates/hir-ty/src/next_solver/structural_normalize.rs @@ -34,7 +34,7 @@ impl<'db> At<'_, 'db> { return Ok(term); } - let new_infer = self.infcx.next_term_var_of_kind(term); + let new_infer = self.infcx.next_term_var_of_kind(term, self.cause.span()); // We simply emit an `alias-eq` goal here, since that will take care of // normalizing the LHS of the projection until it is a rigid projection diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs index 0fd02eb8ca..511259ecd8 100644 --- a/crates/hir-ty/src/next_solver/ty.rs +++ b/crates/hir-ty/src/next_solver/ty.rs @@ -17,7 +17,7 @@ use rustc_type_ir::{ IntVid, Interner, TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, WithCachedTypeInfo, inherent::{ - AdtDef as _, BoundExistentialPredicates, Const as _, GenericArgs as _, IntoKind, ParamLike, + AdtDef as _, BoundExistentialPredicates, GenericArgs as _, IntoKind, ParamLike, Safety as _, SliceLike, Ty as _, }, relate::Relate, @@ -31,8 +31,8 @@ use crate::{ lower::GenericPredicates, next_solver::{ AdtDef, AliasTy, Binder, CallableIdWrapper, Clause, ClauseKind, ClosureIdWrapper, Const, - CoroutineClosureIdWrapper, CoroutineIdWrapper, FnSig, GenericArgKind, PolyFnSig, Region, - TraitRef, TypeAliasIdWrapper, + CoroutineClosureIdWrapper, CoroutineIdWrapper, FnSig, GenericArgKind, PolyFnSig, Predicate, + Region, TraitRef, TypeAliasIdWrapper, abi::Safety, impl_foldable_for_interned_slice, impl_stored_interned, interned_slice, util::{CoroutineArgsExt, IntegerTypeExt}, @@ -817,25 +817,11 @@ impl<'db> Ty<'db> { } pub fn references_non_lt_error<'db, T: TypeVisitableExt<DbInterner<'db>>>(t: &T) -> bool { - t.references_error() && t.visit_with(&mut ReferencesNonLifetimeError).is_break() -} - -struct ReferencesNonLifetimeError; - -impl<'db> TypeVisitor<DbInterner<'db>> for ReferencesNonLifetimeError { - type Result = ControlFlow<()>; - - fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { - if ty.is_ty_error() { ControlFlow::Break(()) } else { ty.super_visit_with(self) } - } - - fn visit_const(&mut self, c: Const<'db>) -> Self::Result { - if c.is_ct_error() { ControlFlow::Break(()) } else { c.super_visit_with(self) } - } + t.has_non_region_error() } pub fn references_only_ty_error<'db, T: TypeVisitableExt<DbInterner<'db>>>(t: &T) -> bool { - t.references_error() && t.visit_with(&mut ReferencesOnlyTyError).is_break() + references_non_lt_error(t) && t.visit_with(&mut ReferencesOnlyTyError).is_break() } struct ReferencesOnlyTyError; @@ -844,7 +830,29 @@ impl<'db> TypeVisitor<DbInterner<'db>> for ReferencesOnlyTyError { type Result = ControlFlow<()>; fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { - if ty.is_ty_error() { ControlFlow::Break(()) } else { ty.super_visit_with(self) } + if !ty.references_non_lt_error() { + ControlFlow::Continue(()) + } else if ty.is_ty_error() { + ControlFlow::Break(()) + } else { + ty.super_visit_with(self) + } + } + + fn visit_const(&mut self, c: Const<'db>) -> Self::Result { + if !references_non_lt_error(&c) { + ControlFlow::Continue(()) + } else { + c.super_visit_with(self) + } + } + + fn visit_predicate(&mut self, p: Predicate<'db>) -> Self::Result { + if !references_non_lt_error(&p) { + ControlFlow::Continue(()) + } else { + p.super_visit_with(self) + } } } @@ -880,6 +888,15 @@ impl<'db> TypeVisitable<DbInterner<'db>> for Ty<'db> { } } +impl<'db> TypeVisitable<DbInterner<'db>> for StoredTy { + fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>( + &self, + visitor: &mut V, + ) -> V::Result { + self.as_ref().visit_with(visitor) + } +} + impl<'db> TypeSuperVisitable<DbInterner<'db>> for Ty<'db> { fn super_visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>( &self, @@ -946,6 +963,18 @@ impl<'db> TypeFoldable<DbInterner<'db>> for Ty<'db> { } } +impl<'db> TypeFoldable<DbInterner<'db>> for StoredTy { + fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + Ok(self.as_ref().try_fold_with(folder)?.store()) + } + fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self { + self.as_ref().fold_with(folder).store() + } +} + impl<'db> TypeSuperFoldable<DbInterner<'db>> for Ty<'db> { fn try_super_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>( self, diff --git a/crates/hir-ty/src/opaques.rs b/crates/hir-ty/src/opaques.rs index 2e85beea91..c78e9d7c5d 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, InferenceResult, + ImplTraitId, InferenceResult, Span, db::{HirDatabase, InternedOpaqueTyId}, lower::{ImplTraitIdx, ImplTraits}, next_solver::{ @@ -140,7 +140,7 @@ pub(crate) fn tait_hidden_types<'db>( } // 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()); + let hidden_type = infcx.insert_type_vars(hidden_type.as_ref(), Span::Dummy); match result.entry(opaque_idx) { la_arena::Entry::Vacant(entry) => { entry.insert(StoredEarlyBinder::bind(hidden_type.store())); diff --git a/crates/hir-ty/src/specialization.rs b/crates/hir-ty/src/specialization.rs index a0bac48250..7e4d3a8354 100644 --- a/crates/hir-ty/src/specialization.rs +++ b/crates/hir-ty/src/specialization.rs @@ -7,6 +7,7 @@ use hir_def::{ use tracing::debug; use crate::{ + Span, db::HirDatabase, lower::GenericPredicates, next_solver::{ @@ -91,7 +92,7 @@ fn specializes_query( let mut ocx = ObligationCtxt::new(&infcx); - let parent_args = infcx.fresh_args_for_item(parent_impl_def_id.into()); + let parent_args = infcx.fresh_args_for_item(Span::Dummy, parent_impl_def_id.into()); let parent_impl_trait_ref = db .impl_trait(parent_impl_def_id) .expect("expected source impl to be a trait impl") diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index 0dc834ddcc..ad668f2eee 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -21,6 +21,7 @@ use rustc_type_ir::{ }; use crate::{ + Span, db::HirDatabase, next_solver::{ DbInterner, GenericArgs, ParamEnv, StoredClauses, Ty, TyKind, @@ -121,7 +122,7 @@ pub fn implements_trait_unique<'db>( trait_: TraitId, ) -> bool { implements_trait_unique_impl(db, env, trait_, &mut |infcx| { - infcx.fill_rest_fresh_args(trait_.into(), [ty.into()]) + infcx.fill_rest_fresh_args(Span::Dummy, trait_.into(), [ty.into()]) }) } diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 9943b718fd..f9cf05e73a 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -504,6 +504,8 @@ fn resolve_impl_trait_item<'db>( traits_in_scope: &traits_in_scope, edition: krate.edition(db), features, + call_span: hir_ty::Span::Dummy, + receiver_span: hir_ty::Span::Dummy, }; let resolution = ctx.probe_for_name(method_resolution::Mode::Path, name.clone(), ty.ty); let resolution = match resolution { diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 8f9465cf1b..18f28541af 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -6,9 +6,9 @@ use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_def::{ - DefWithBodyId, GenericParamId, SyntheticSyntax, + DefWithBodyId, GenericParamId, HasModule, SyntheticSyntax, expr_store::{ - ExprOrPatPtr, ExprOrPatSource, ExpressionStoreSourceMap, hir_assoc_type_binding_to_ast, + ExprOrPatPtr, ExpressionStoreSourceMap, hir_assoc_type_binding_to_ast, hir_generic_arg_to_ast, hir_segment_to_ast_segment, }, hir::ExprOrPatId, @@ -19,6 +19,7 @@ use hir_ty::{ PathLoweringDiagnostic, TyLoweringDiagnostic, TyLoweringDiagnosticKind, db::HirDatabase, diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, + display::{DisplayTarget, HirDisplay}, }; use syntax::{ AstNode, AstPtr, SyntaxError, SyntaxNodePtr, TextRange, @@ -108,7 +109,7 @@ diagnostics![AnyDiagnostic<'db> -> IncorrectGenericsOrder, MissingLifetime, ElidedLifetimesInPath, - TypeMustBeKnown, + TypeMustBeKnown<'db>, ]; #[derive(Debug)] @@ -446,8 +447,9 @@ pub struct ElidedLifetimesInPath { } #[derive(Debug)] -pub struct TypeMustBeKnown { - pub at_point: ExprOrPatSource, +pub struct TypeMustBeKnown<'db> { + pub at_point: InFile<AstPtr<Either<ast::Type, Either<ast::Expr, ast::Pat>>>>, + pub top_term: Option<Either<Type<'db>, String>>, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -631,6 +633,12 @@ impl<'db> AnyDiagnostic<'db> { .inspect_err(|_| stdx::never!("inference diagnostic in desugared pattern")) .ok() }; + let type_syntax = |pat| { + source_map + .type_syntax(pat) + .inspect_err(|_| stdx::never!("inference diagnostic in desugared type")) + .ok() + }; let expr_or_pat_syntax = |id| match id { ExprOrPatId::ExprId(expr) => expr_syntax(expr), ExprOrPatId::PatId(pat) => pat_syntax(pat), @@ -806,8 +814,29 @@ impl<'db> AnyDiagnostic<'db> { let lhs = expr_syntax(lhs)?; InvalidLhsOfAssignment { lhs }.into() } - &InferenceDiagnostic::TypeMustBeKnown { at_point } => { - TypeMustBeKnown { at_point: expr_or_pat_syntax(at_point)? }.into() + &InferenceDiagnostic::TypeMustBeKnown { at_point, ref top_term } => { + let at_point = match at_point { + hir_ty::Span::ExprId(idx) => expr_syntax(idx)?.map(|it| it.wrap_right()), + hir_ty::Span::PatId(idx) => pat_syntax(idx)?.map(|it| it.wrap_right()), + hir_ty::Span::TypeRefId(idx) => type_syntax(idx)?.map(|it| it.wrap_left()), + hir_ty::Span::Dummy => unreachable!( + "should never create TypeMustBeKnown diagnostic for dummy spans" + ), + }; + let top_term = top_term.as_ref().map(|top_term| match top_term.as_ref().kind() { + rustc_type_ir::GenericArgKind::Type(ty) => Either::Left(Type { + ty, + env: crate::body_param_env_from_has_crate(db, def), + }), + // FIXME: Printing the const to string is definitely not the correct thing to do here. + rustc_type_ir::GenericArgKind::Const(konst) => Either::Right( + konst.display(db, DisplayTarget::from_crate(db, def.krate(db))).to_string(), + ), + rustc_type_ir::GenericArgKind::Lifetime(_) => { + unreachable!("we currently don't emit TypeMustBeKnown for lifetimes") + } + }); + TypeMustBeKnown { at_point, top_term }.into() } }) } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 11598f2a10..8cc82113b3 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1525,7 +1525,7 @@ impl Struct { } pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedStruct<'db> { - let args = infer_ctxt.fresh_args_for_item(self.id.into()); + let args = infer_ctxt.fresh_args_for_item(hir_ty::Span::Dummy, self.id.into()); InstantiatedStruct { inner: self, args } } } @@ -1804,8 +1804,10 @@ impl EnumVariant { } pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedVariant<'db> { - let args = - infer_ctxt.fresh_args_for_item(self.parent_enum(infer_ctxt.interner.db()).id.into()); + let args = infer_ctxt.fresh_args_for_item( + hir_ty::Span::Dummy, + self.parent_enum(infer_ctxt.interner.db()).id.into(), + ); InstantiatedVariant { inner: self, args } } } @@ -4793,7 +4795,7 @@ impl ConstParam { } pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { - Type::new(db, self.id.parent(), db.const_param_ty_ns(self.id)) + Type::new(db, self.id.parent(), db.const_param_ty(self.id)) } pub fn default( @@ -6191,6 +6193,8 @@ impl<'db> Type<'db> { traits_in_scope, edition: resolver.krate().data(db).edition, features, + call_span: hir_ty::Span::Dummy, + receiver_span: hir_ty::Span::Dummy, }; f(&ctx) } @@ -6217,7 +6221,7 @@ impl<'db> Type<'db> { self.with_method_resolution(db, scope.resolver(), traits_in_scope, |ctx| { // There should be no inference vars in types passed here let canonical = hir_ty::replace_errors_with_variables(ctx.infcx.interner, &self.ty); - let (self_ty, _) = ctx.infcx.instantiate_canonical(&canonical); + let (self_ty, _) = ctx.infcx.instantiate_canonical(hir_ty::Span::Dummy, &canonical); match name { Some(name) => { @@ -6325,7 +6329,7 @@ impl<'db> Type<'db> { self.with_method_resolution(db, scope.resolver(), traits_in_scope, |ctx| { // There should be no inference vars in types passed here let canonical = hir_ty::replace_errors_with_variables(ctx.infcx.interner, &self.ty); - let (self_ty, _) = ctx.infcx.instantiate_canonical(&canonical); + let (self_ty, _) = ctx.infcx.instantiate_canonical(hir_ty::Span::Dummy, &canonical); match name { Some(name) => { diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 9d97dc7421..252f4ac7f2 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -36,20 +36,19 @@ use hir_ty::{ diagnostics::unsafe_operations, infer_query_with_inspect, next_solver::{ - AnyImplId, DbInterner, Span, + AnyImplId, DbInterner, format_proof_tree::{ProofTreeData, dump_proof_tree_structured}, }, }; use intern::{Interned, Symbol, sym}; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; -use rustc_type_ir::inherent::Span as _; use smallvec::{SmallVec, smallvec}; use span::{FileId, SyntaxContext}; use stdx::{TupleExt, always}; use syntax::{ - AstNode, AstToken, Direction, SmolStr, SmolStrBuilder, SyntaxElement, SyntaxKind, SyntaxNode, - SyntaxNodePtr, SyntaxToken, T, TextRange, TextSize, + AstNode, AstPtr, AstToken, Direction, SmolStr, SmolStrBuilder, SyntaxElement, SyntaxKind, + SyntaxNode, SyntaxNodePtr, SyntaxToken, T, TextRange, TextSize, algo::skip_trivia_token, ast::{self, HasAttrs as _, HasGenericParams}, }; @@ -544,6 +543,10 @@ impl<'db> SemanticsImpl<'db> { node } + pub fn to_node<N: AstNode>(&self, ptr: InFile<AstPtr<N>>) -> N { + ptr.value.to_node(&self.parse_or_expand(ptr.file_id)) + } + pub fn expand(&self, file_id: MacroCallId) -> ExpandResult<SyntaxNode> { let res = self.db.parse_macro_expansion(file_id).map(|it| it.0.syntax_node()); self.cache(res.value.clone(), file_id.into()); @@ -2459,7 +2462,8 @@ impl<'db> SemanticsImpl<'db> { if result.is_err() && let Some(tree) = proof_tree { - let data = dump_proof_tree_structured(tree, Span::dummy(), infer_ctxt); + let data = + dump_proof_tree_structured(tree, hir_ty::Span::Dummy, infer_ctxt); RESULT.with(|ctx| ctx.borrow_mut().push(data)); } }), diff --git a/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs b/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs index 2a7b0098ed..7cadff84fb 100644 --- a/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs +++ b/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs @@ -52,6 +52,7 @@ async fn bar() { fn await_inside_closure() { check_diagnostics( r#" +//- minicore: future async fn foo() {} async fn bar() { @@ -66,6 +67,7 @@ async fn bar() { fn await_inside_async_block() { check_diagnostics( r#" +//- minicore: future async fn foo() {} fn bar() { @@ -79,6 +81,7 @@ fn bar() { fn await_in_complex_context() { check_diagnostics( r#" +//- minicore: future async fn foo() {} fn bar() { diff --git a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs index cbcaab6c74..02f3cab565 100644 --- a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs +++ b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs @@ -147,7 +147,7 @@ fn test() { r#" //- minicore: option, try fn test() { - try { + let _: Option<_> = try { || { let x = Some(2); Some(x?) diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs index 5410f8b58a..5a456504e1 100644 --- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -1006,18 +1006,18 @@ fn func() { #![allow(unused_variables)] #[warn(nonstandard_style)] fn foo() { - let BAR; + let BAR: i32; // ^^^ 💡 warn: Variable `BAR` should have snake_case name, e.g. `bar` #[allow(non_snake_case)] - let FOO; + let FOO: i32; } #[warn(nonstandard_style)] fn foo() { - let BAR; + let BAR: i32; // ^^^ 💡 warn: Variable `BAR` should have snake_case name, e.g. `bar` #[expect(non_snake_case)] - let FOO; + let FOO: i32; #[allow(non_snake_case)] struct qux; // ^^^ 💡 warn: Structure `qux` should have UpperCamelCase name, e.g. `Qux` @@ -1060,7 +1060,7 @@ mod FINE_WITH_BAD_CASE; struct QUX; const foo: i32 = 0; fn BAR() { - let BAZ; + let BAZ: i32; _ = BAZ; } "#, diff --git a/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs b/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs index 25220704e0..2a31a41fbc 100644 --- a/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs +++ b/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs @@ -43,6 +43,8 @@ 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}>` } "#, @@ -51,6 +53,10 @@ 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> { @@ -60,8 +66,12 @@ 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}>` } "#, @@ -127,6 +137,8 @@ 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<(), _>` } "#, ); diff --git a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs index 4c0985c7ae..b900a8f5cc 100644 --- a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs +++ b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs @@ -453,6 +453,8 @@ fn g() { b::<1, 3>(0, 2); b(0, 1, 2); + // ^ error: type annotations needed + // | full type: `fn b<_, _>(u8, u8)` //^ error: expected 4 arguments, found 3 } "#, diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index 85368cc09f..117702923b 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -293,12 +293,15 @@ fn baz(s: S) -> i32 { #[test] fn missing_record_pat_field_box() { check_diagnostics( - r" + r#" +#![feature(lang_items)] +#[lang = "owned_box"] +struct Box<T>(T); struct S { s: Box<u32> } fn x(a: S) { let S { box s } = a; } -", +"#, ) } diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 355617a2b1..a845e0b59a 100644 --- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -1340,6 +1340,7 @@ pub fn foo<T: Foo>(_: T) -> (T::Out,) { loop { } } fn main() { let _x = foo(2); + // ^^ error: type annotations needed } "#, ); diff --git a/crates/ide-diagnostics/src/handlers/type_must_be_known.rs b/crates/ide-diagnostics/src/handlers/type_must_be_known.rs index 4b72497408..5363f4a5ce 100644 --- a/crates/ide-diagnostics/src/handlers/type_must_be_known.rs +++ b/crates/ide-diagnostics/src/handlers/type_must_be_known.rs @@ -1,17 +1,56 @@ +use either::Either; +use hir::HirDisplay; +use stdx::format_to; +use syntax::{AstNode, SyntaxNodePtr, ast}; + use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: type-must-be-known // // This diagnostic is triggered when rust-analyzer cannot infer some type. -pub(crate) fn type_must_be_known( - ctx: &DiagnosticsContext<'_>, - d: &hir::TypeMustBeKnown, +pub(crate) fn type_must_be_known<'db>( + ctx: &DiagnosticsContext<'db>, + d: &hir::TypeMustBeKnown<'db>, ) -> Diagnostic { + let mut at_point = d.at_point.map(|it| it.syntax_node_ptr()); + let mut top_term = d.top_term.clone(); + + // Do some adjustments to the node: FIXME: We should probably do that at the emitting site. + let node = ctx.sema.to_node(d.at_point); + if let Either::Right(Either::Left(expr)) = &node + && let Some(Either::Left(top_ty)) = &d.top_term + && let Some(expr_ty) = ctx.sema.type_of_expr(expr) + && expr_ty.original == *top_ty + && !top_ty.is_unknown() + && let Some(parent) = expr.syntax().parent().and_then(ast::CallExpr::cast) + && let Some(callable) = top_ty.as_callable(ctx.db()) + && let ret_ty = callable.return_type() + && ret_ty.contains_unknown() + { + top_term = Some(Either::Left(ret_ty)); + at_point.value = SyntaxNodePtr::new(parent.syntax()); + } + + let message = match &top_term { + Some(top_term) if !matches!(top_term, Either::Left(ty) if ty.is_unknown()) => { + let mut message = "type annotations needed\nfull type: `".to_owned(); + match top_term { + Either::Left(ty) => { + format_to!(message, "{}", ty.display(ctx.db(), ctx.display_target)) + } + Either::Right(konst) => message.push_str(konst), + } + message.push_str("`\n"); + message + } + Some(_) => "type annotations needed".to_owned(), + None => "type annotations needed; type must be known at this point".to_owned(), + }; Diagnostic::new_with_syntax_node_ptr( ctx, DiagnosticCode::RustcHardError("E0282"), - "type annotations needed; type must be known at this point", - d.at_point.map(|it| it.into()), + message, + at_point, ) } @@ -20,7 +59,7 @@ mod tests { use crate::tests::check_diagnostics; #[test] - fn smoke_test() { + fn some_expressions_require_knowing_type() { check_diagnostics( r#" fn foo() { @@ -36,4 +75,32 @@ fn foo() { "#, ); } + + #[test] + fn binding_without_type() { + check_diagnostics( + r#" +fn any<T>() -> T { loop {} } +fn foo() { + let _x = any(); + // ^^^^^ error: type annotations needed +} + "#, + ); + } + + #[test] + fn struct_with_generic() { + check_diagnostics( + r#" +struct X<T>(T); +fn any<T>() -> X<T> { loop {} } +fn foo() { + let _x = any(); + // ^^^^^ error: type annotations needed + // | full type: `X<{unknown}>` +} + "#, + ); + } } diff --git a/crates/ide-diagnostics/src/handlers/typed_hole.rs b/crates/ide-diagnostics/src/handlers/typed_hole.rs index fd1674e2a4..ddd1dd402e 100644 --- a/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -166,6 +166,8 @@ fn t<T>() -> T { loop {} } r#" fn main() { let _x = [(); _]; + // ^ error: type annotations needed + // | full type: `[(); _]` // FIXME: This should trigger error // let _y: [(); 10] = [(); _]; _ = 0; diff --git a/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs b/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs index 9883bcc84f..301613e920 100644 --- a/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs +++ b/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs @@ -2722,6 +2722,13 @@ fn foo() { tracing::error!(); } "#, - &["E0432", "inactive-code", "unresolved-macro-call", "syntax-error", "macro-error"], + &[ + "E0432", + "E0282", + "inactive-code", + "unresolved-macro-call", + "syntax-error", + "macro-error", + ], ); } diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs index de8c3f2e55..9088efeca4 100644 --- a/crates/macros/src/lib.rs +++ b/crates/macros/src/lib.rs @@ -5,7 +5,7 @@ use syn::parse_quote; use synstructure::decl_derive; decl_derive!( - [TypeFoldable, attributes(type_foldable)] => + [TypeFoldable, attributes(type_foldable, type_visitable)] => /// Derives `TypeFoldable` for the annotated `struct` or `enum` (`union` is not supported). /// /// The fold will produce a value of the same struct or enum variant as the input, with @@ -102,8 +102,10 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke vi.construct(|_, index| { let bind = &bindings[index]; - // retain value of fields with #[type_foldable(identity)] - if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { + // retain value of fields with #[type_foldable(identity)] or #[type_visitable(ignore)] + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") + || has_ignore_attr(&bind.ast().attrs, "type_visitable", "ignore") + { bind.to_token_stream() } else { quote! { @@ -118,8 +120,10 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke vi.construct(|_, index| { let bind = &bindings[index]; - // retain value of fields with #[type_foldable(identity)] - if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { + // retain value of fields with #[type_foldable(identity)] or #[type_visitable(ignore)] + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") + || has_ignore_attr(&bind.ast().attrs, "type_visitable", "ignore") + { bind.to_token_stream() } else { quote! { diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index c447870e96..33a20951da 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -67,7 +67,7 @@ //! size_of: sized //! sized: //! slice: -//! str: +//! str: sized, result //! sync: sized //! transmute: //! try: infallible @@ -1726,6 +1726,22 @@ pub mod iter { } } + pub struct Map<I, F> { + iter: I, + f: F, + } + impl<B, I: Iterator, F> Iterator for Map<I, F> + where + F: FnMut(I::Item) -> B, + { + type Item = B; + + #[inline] + fn next(&mut self) -> B { + loop {} + } + } + pub struct FilterMap<I, F> { iter: I, f: F, @@ -1800,6 +1816,13 @@ pub mod iter { { loop {} } + fn map<B, F>(self, _f: F) -> crate::iter::Map<Self, F> + where + Self: Sized, + F: FnMut(Self::Item) -> B, + { + loop {} + } fn filter_map<B, F>(self, _f: F) -> crate::iter::FilterMap<Self, F> where Self: Sized, |