diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs index 6a7ea8a990a..c749bf570c3 100644 --- a/crates/hir-ty/src/autoderef.rs +++ b/crates/hir-ty/src/autoderef.rs @@ -3,8 +3,6 @@ //! reference to a type with the field `bar`. This is an approximation of the //! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs). -use std::sync::Arc; - use chalk_ir::cast::Cast; use hir_def::{ lang_item::{LangItem, LangItemTarget}, @@ -13,10 +11,7 @@ use hir_def::{ use hir_expand::name::name; use limit::Limit; -use crate::{ - db::HirDatabase, infer::unify::InferenceTable, Canonical, Goal, Interner, ProjectionTyExt, - TraitEnvironment, Ty, TyBuilder, TyKind, -}; +use crate::{infer::unify::InferenceTable, Goal, Interner, ProjectionTyExt, Ty, TyBuilder, TyKind}; static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10); @@ -27,15 +22,15 @@ pub(crate) enum AutoderefKind { } #[derive(Debug)] -pub(crate) struct Autoderef<'a, 'db> { - pub(crate) table: &'a mut InferenceTable<'db>, +pub struct Autoderef<'a, 'db> { + pub table: &'a mut InferenceTable<'db>, ty: Ty, at_start: bool, steps: Vec<(AutoderefKind, Ty)>, } impl<'a, 'db> Autoderef<'a, 'db> { - pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty) -> Self { + pub fn new(table: &'a mut InferenceTable<'db>, ty: Ty) -> Self { let ty = table.resolve_ty_shallow(&ty); Autoderef { table, ty, at_start: true, steps: Vec::new() } } @@ -86,22 +81,6 @@ pub(crate) fn autoderef_step( } } -// FIXME: replace uses of this with Autoderef above -pub fn autoderef( - db: &dyn HirDatabase, - env: Arc, - ty: Canonical, -) -> impl Iterator> + '_ { - let mut table = InferenceTable::new(db, env); - let ty = table.instantiate_canonical(ty); - let mut autoderef = Autoderef::new(&mut table, ty); - let mut v = Vec::new(); - while let Some((ty, _steps)) = autoderef.next() { - v.push(autoderef.table.canonicalize(ty).value); - } - v.into_iter() -} - pub(crate) fn builtin_deref<'ty>( table: &mut InferenceTable<'_>, ty: &'ty Ty, diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 6c1214c1726..73f3ba1e320 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -28,11 +28,12 @@ use crate::{ infer::{ coerce::CoerceMany, find_continuable, pat::contains_explicit_ref_binding, BreakableKind, }, + lang_items::lang_items_for_bin_op, lower::{ const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode, }, mapping::{from_chalk, ToChalk}, - method_resolution::{self, lang_items_for_bin_op, VisibleFromModule}, + method_resolution::{self, VisibleFromModule}, primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, traits::FnTrait, @@ -792,7 +793,7 @@ impl<'a> InferenceContext<'a> { let canonicalized = self.canonicalize(base_ty.clone()); let receiver_adjustments = method_resolution::resolve_indexing_op( self.db, - self.table.trait_env.clone(), + &mut self.table, canonicalized.value, index_trait, ); diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index f0e0714e1db..b3428938e0d 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -32,11 +32,11 @@ impl<'a> InferenceContext<'a> { } #[derive(Debug, Clone)] -pub(crate) struct Canonicalized +pub struct Canonicalized where T: HasInterner, { - pub(crate) value: Canonical, + pub value: Canonical, free_vars: Vec, } @@ -140,7 +140,7 @@ bitflags::bitflags! { type ChalkInferenceTable = chalk_solve::infer::InferenceTable; #[derive(Clone)] -pub(crate) struct InferenceTable<'a> { +pub struct InferenceTable<'a> { pub(crate) db: &'a dyn HirDatabase, pub(crate) trait_env: Arc, var_unification_table: ChalkInferenceTable, @@ -155,7 +155,7 @@ pub(crate) struct InferenceTableSnapshot { } impl<'a> InferenceTable<'a> { - pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc) -> Self { + pub fn new(db: &'a dyn HirDatabase, trait_env: Arc) -> Self { InferenceTable { db, trait_env, @@ -204,7 +204,7 @@ impl<'a> InferenceTable<'a> { .intern(Interner) } - pub(crate) fn canonicalize + HasInterner>( + pub fn canonicalize + HasInterner>( &mut self, t: T, ) -> Canonicalized @@ -320,7 +320,7 @@ impl<'a> InferenceTable<'a> { ) } - pub(crate) fn instantiate_canonical(&mut self, canonical: Canonical) -> T + pub fn instantiate_canonical(&mut self, canonical: Canonical) -> T where T: HasInterner + TypeFoldable + std::fmt::Debug, { diff --git a/crates/hir-ty/src/lang_items.rs b/crates/hir-ty/src/lang_items.rs index 5308c72161b..28e5f6df063 100644 --- a/crates/hir-ty/src/lang_items.rs +++ b/crates/hir-ty/src/lang_items.rs @@ -1,6 +1,7 @@ //! Functions to detect special lang items use hir_def::{lang_item::LangItem, AdtId, HasModule}; +use hir_expand::name::Name; use crate::db::HirDatabase; @@ -17,3 +18,52 @@ pub fn is_unsafe_cell(adt: AdtId, db: &dyn HirDatabase) -> bool { db.lang_item(krate, LangItem::UnsafeCell).and_then(|it| it.as_struct()).map(AdtId::from); Some(adt) == box_adt } + +pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> { + use hir_expand::name; + use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering}; + Some(match op { + BinaryOp::LogicOp(_) => return None, + BinaryOp::ArithOp(aop) => match aop { + ArithOp::Add => (name![add], LangItem::Add), + ArithOp::Mul => (name![mul], LangItem::Mul), + ArithOp::Sub => (name![sub], LangItem::Sub), + ArithOp::Div => (name![div], LangItem::Div), + ArithOp::Rem => (name![rem], LangItem::Rem), + ArithOp::Shl => (name![shl], LangItem::Shl), + ArithOp::Shr => (name![shr], LangItem::Shr), + ArithOp::BitXor => (name![bitxor], LangItem::BitXor), + ArithOp::BitOr => (name![bitor], LangItem::BitOr), + ArithOp::BitAnd => (name![bitand], LangItem::BitAnd), + }, + BinaryOp::Assignment { op: Some(aop) } => match aop { + ArithOp::Add => (name![add_assign], LangItem::AddAssign), + ArithOp::Mul => (name![mul_assign], LangItem::MulAssign), + ArithOp::Sub => (name![sub_assign], LangItem::SubAssign), + ArithOp::Div => (name![div_assign], LangItem::DivAssign), + ArithOp::Rem => (name![rem_assign], LangItem::RemAssign), + ArithOp::Shl => (name![shl_assign], LangItem::ShlAssign), + ArithOp::Shr => (name![shr_assign], LangItem::ShrAssign), + ArithOp::BitXor => (name![bitxor_assign], LangItem::BitXorAssign), + ArithOp::BitOr => (name![bitor_assign], LangItem::BitOrAssign), + ArithOp::BitAnd => (name![bitand_assign], LangItem::BitAndAssign), + }, + BinaryOp::CmpOp(cop) => match cop { + CmpOp::Eq { negated: false } => (name![eq], LangItem::PartialEq), + CmpOp::Eq { negated: true } => (name![ne], LangItem::PartialEq), + CmpOp::Ord { ordering: Ordering::Less, strict: false } => { + (name![le], LangItem::PartialOrd) + } + CmpOp::Ord { ordering: Ordering::Less, strict: true } => { + (name![lt], LangItem::PartialOrd) + } + CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { + (name![ge], LangItem::PartialOrd) + } + CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { + (name![gt], LangItem::PartialOrd) + } + }, + BinaryOp::Assignment { op: None } => return None, + }) +} diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index e10dfa2278d..1cab32e958c 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -7,12 +7,9 @@ macro_rules! eprintln { ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; } -mod autoderef; mod builder; mod chalk_db; mod chalk_ext; -pub mod consteval; -pub mod mir; mod infer; mod inhabitedness; mod interner; @@ -20,14 +17,18 @@ mod lower; mod mapping; mod tls; mod utils; + +pub mod autoderef; +pub mod consteval; pub mod db; pub mod diagnostics; pub mod display; +pub mod lang_items; +pub mod layout; pub mod method_resolution; +pub mod mir; pub mod primitive; pub mod traits; -pub mod layout; -pub mod lang_items; #[cfg(test)] mod tests; @@ -51,16 +52,14 @@ use rustc_hash::FxHashSet; use traits::FnTrait; use utils::Generics; -use crate::{ - consteval::unknown_const, db::HirDatabase, infer::unify::InferenceTable, utils::generics, -}; +use crate::{consteval::unknown_const, db::HirDatabase, utils::generics}; -pub use autoderef::autoderef; +pub use autoderef::Autoderef; pub use builder::{ParamKind, TyBuilder}; pub use chalk_ext::*; pub use infer::{ - could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, - InferenceResult, OverloadedDeref, PointerCast, + could_coerce, could_unify, unify::InferenceTable, Adjust, Adjustment, AutoBorrow, BindingMode, + InferenceDiagnostic, InferenceResult, OverloadedDeref, PointerCast, }; pub use interner::Interner; pub use lower::{ diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 94c0d3c0c19..e08c44f0a04 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -7,9 +7,8 @@ use std::{ops::ControlFlow, sync::Arc}; use base_db::{CrateId, Edition}; use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause}; use hir_def::{ - data::ImplData, item_scope::ItemScope, lang_item::LangItem, nameres::DefMap, AssocItemId, - BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, - ModuleId, TraitId, + data::ImplData, item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId, + FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId, }; use hir_expand::name::Name; use rustc_hash::{FxHashMap, FxHashSet}; @@ -451,55 +450,6 @@ pub fn def_crates( } } -pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> { - use hir_expand::name; - use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering}; - Some(match op { - BinaryOp::LogicOp(_) => return None, - BinaryOp::ArithOp(aop) => match aop { - ArithOp::Add => (name![add], LangItem::Add), - ArithOp::Mul => (name![mul], LangItem::Mul), - ArithOp::Sub => (name![sub], LangItem::Sub), - ArithOp::Div => (name![div], LangItem::Div), - ArithOp::Rem => (name![rem], LangItem::Rem), - ArithOp::Shl => (name![shl], LangItem::Shl), - ArithOp::Shr => (name![shr], LangItem::Shr), - ArithOp::BitXor => (name![bitxor], LangItem::BitXor), - ArithOp::BitOr => (name![bitor], LangItem::BitOr), - ArithOp::BitAnd => (name![bitand], LangItem::BitAnd), - }, - BinaryOp::Assignment { op: Some(aop) } => match aop { - ArithOp::Add => (name![add_assign], LangItem::AddAssign), - ArithOp::Mul => (name![mul_assign], LangItem::MulAssign), - ArithOp::Sub => (name![sub_assign], LangItem::SubAssign), - ArithOp::Div => (name![div_assign], LangItem::DivAssign), - ArithOp::Rem => (name![rem_assign], LangItem::RemAssign), - ArithOp::Shl => (name![shl_assign], LangItem::ShlAssign), - ArithOp::Shr => (name![shr_assign], LangItem::ShrAssign), - ArithOp::BitXor => (name![bitxor_assign], LangItem::BitXorAssign), - ArithOp::BitOr => (name![bitor_assign], LangItem::BitOrAssign), - ArithOp::BitAnd => (name![bitand_assign], LangItem::BitAndAssign), - }, - BinaryOp::CmpOp(cop) => match cop { - CmpOp::Eq { negated: false } => (name![eq], LangItem::PartialEq), - CmpOp::Eq { negated: true } => (name![ne], LangItem::PartialEq), - CmpOp::Ord { ordering: Ordering::Less, strict: false } => { - (name![le], LangItem::PartialOrd) - } - CmpOp::Ord { ordering: Ordering::Less, strict: true } => { - (name![lt], LangItem::PartialOrd) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { - (name![ge], LangItem::PartialOrd) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { - (name![gt], LangItem::PartialOrd) - } - }, - BinaryOp::Assignment { op: None } => return None, - }) -} - /// Look up the method with the given name. pub(crate) fn lookup_method( db: &dyn HirDatabase, @@ -1310,16 +1260,18 @@ fn iterate_inherent_methods( /// Returns the receiver type for the index trait call. pub fn resolve_indexing_op( db: &dyn HirDatabase, - env: Arc, + table: &mut InferenceTable<'_>, ty: Canonical, index_trait: TraitId, ) -> Option { - let mut table = InferenceTable::new(db, env.clone()); let ty = table.instantiate_canonical(ty); - let deref_chain = autoderef_method_receiver(&mut table, ty); + let deref_chain = autoderef_method_receiver(table, ty); for (ty, adj) in deref_chain { - let goal = generic_implements_goal(db, env.clone(), index_trait, &ty); - if db.trait_solve(env.krate, env.block, goal.cast(Interner)).is_some() { + let goal = generic_implements_goal(db, table.trait_env.clone(), index_trait, &ty); + if db + .trait_solve(table.trait_env.krate, table.trait_env.block, goal.cast(Interner)) + .is_some() + { return Some(adj); } } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index ea851a11a85..5cad8315874 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -57,7 +57,7 @@ use hir_def::{ }; use hir_expand::{name::name, MacroCallKind}; use hir_ty::{ - all_super_traits, autoderef, + all_super_traits, consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, diagnostics::BodyValidationDiagnostic, display::HexifiedConst, @@ -66,9 +66,10 @@ use hir_ty::{ mir::{self, interpret_mir}, primitive::UintTy, traits::FnTrait, - AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, - GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution, - TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause, + AliasTy, Autoderef, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, + GenericArgData, InferenceTable, Interner, ParamKind, QuantifiedWhereClause, Scalar, + Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, + WhereClause, }; use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; @@ -3517,8 +3518,15 @@ impl Type { fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { // There should be no inference vars in types passed here let canonical = hir_ty::replace_errors_with_variables(&self.ty); - let environment = self.env.clone(); - autoderef(db, environment, canonical).map(|canonical| canonical.value) + + let mut table = InferenceTable::new(db, self.env.clone()); + let ty = table.instantiate_canonical(canonical); + let mut autoderef = Autoderef::new(&mut table, ty); + let mut v = Vec::new(); + while let Some((ty, _steps)) = autoderef.next() { + v.push(autoderef.table.canonicalize(ty).value); + } + v.into_iter().map(|canonical| canonical.value) } // This would be nicer if it just returned an iterator, but that runs into diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 5b18e445727..4d33c71fdd8 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -39,7 +39,8 @@ use hir_ty::{ record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions, UnsafeExpr, }, - method_resolution::{self, lang_items_for_bin_op}, + lang_items::lang_items_for_bin_op, + method_resolution::{self}, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, }; use itertools::Itertools;