diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index b515472501..0e4d20c07e 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -347,6 +347,7 @@ pub mod known { recursion_limit, feature, // known methods of lang items + call_once, eq, ne, ge, diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs index d5ef0c22de..8faef7bf71 100644 --- a/crates/hir-ty/src/builder.rs +++ b/crates/hir-ty/src/builder.rs @@ -63,7 +63,7 @@ impl TyBuilder { } fn build_internal(self) -> (D, Substitution) { - assert_eq!(self.vec.len(), self.param_kinds.len()); + assert_eq!(self.vec.len(), self.param_kinds.len(), "{:?}", &self.param_kinds); for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) { self.assert_match_kind(a, e); } @@ -282,6 +282,21 @@ impl TyBuilder { let (Tuple(size), subst) = self.build_internal(); TyKind::Tuple(size, subst).intern(Interner) } + + pub fn tuple_with(elements: I) -> Ty + where + I: IntoIterator, + ::IntoIter: ExactSizeIterator, + { + let elements = elements.into_iter(); + let len = elements.len(); + let mut b = + TyBuilder::new(Tuple(len), iter::repeat(ParamKind::Type).take(len).collect(), None); + for e in elements { + b = b.push(e); + } + b.build() + } } impl TyBuilder { diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 4402c75947..571b3e9686 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -938,19 +938,24 @@ impl<'a> InferenceContext<'a> { self.db.trait_data(trait_).associated_type_by_name(&name![Item]) } - fn resolve_ops_try_ok(&self) -> Option { - let trait_ = self.resolve_lang_item(LangItem::Try)?.as_trait()?; + fn resolve_output_on(&self, trait_: TraitId) -> Option { self.db.trait_data(trait_).associated_type_by_name(&name![Output]) } + fn resolve_lang_trait(&self, lang: LangItem) -> Option { + self.resolve_lang_item(lang)?.as_trait() + } + + fn resolve_ops_try_output(&self) -> Option { + self.resolve_output_on(self.resolve_lang_trait(LangItem::Try)?) + } + fn resolve_ops_neg_output(&self) -> Option { - let trait_ = self.resolve_lang_item(LangItem::Neg)?.as_trait()?; - self.db.trait_data(trait_).associated_type_by_name(&name![Output]) + self.resolve_output_on(self.resolve_lang_trait(LangItem::Neg)?) } fn resolve_ops_not_output(&self) -> Option { - let trait_ = self.resolve_lang_item(LangItem::Not)?.as_trait()?; - self.db.trait_data(trait_).associated_type_by_name(&name![Output]) + self.resolve_output_on(self.resolve_lang_trait(LangItem::Not)?) } fn resolve_future_future_output(&self) -> Option { @@ -960,7 +965,7 @@ impl<'a> InferenceContext<'a> { .lookup(self.db.upcast()) .container else { return None }; - self.db.trait_data(trait_).associated_type_by_name(&name![Output]) + self.resolve_output_on(trait_) } fn resolve_boxed_box(&self) -> Option { @@ -998,13 +1003,8 @@ impl<'a> InferenceContext<'a> { Some(struct_.into()) } - fn resolve_ops_index(&self) -> Option { - self.resolve_lang_item(LangItem::Index)?.as_trait() - } - fn resolve_ops_index_output(&self) -> Option { - let trait_ = self.resolve_ops_index()?; - self.db.trait_data(trait_).associated_type_by_name(&name![Output]) + self.resolve_output_on(self.resolve_lang_trait(LangItem::Index)?) } fn resolve_va_list(&self) -> Option { diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 7ae85d2061..7b9bf0c5cf 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -13,11 +13,12 @@ use hir_def::{ ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp, }, generics::TypeOrConstParamData, + lang_item::LangItem, path::{GenericArg, GenericArgs}, resolver::resolver_for_expr, ConstParamId, FieldId, ItemContainerId, Lookup, }; -use hir_expand::name::Name; +use hir_expand::name::{name, Name}; use stdx::always; use syntax::ast::RangeOp; @@ -157,7 +158,8 @@ impl<'a> InferenceContext<'a> { } // The ok-ish type that is expected from the last expression - let ok_ty = self.resolve_associated_type(try_ty.clone(), self.resolve_ops_try_ok()); + let ok_ty = + self.resolve_associated_type(try_ty.clone(), self.resolve_ops_try_output()); self.with_breakable_ctx(BreakableKind::Block, ok_ty.clone(), None, |this| { this.infer_expr(*body, &Expectation::has_type(ok_ty)); @@ -331,11 +333,18 @@ impl<'a> InferenceContext<'a> { derefed_callee.callable_sig(self.db).map_or(false, |sig| sig.is_varargs) || res.is_none(); let (param_tys, ret_ty) = match res { - Some(res) => { + Some((func, params, ret_ty)) => { let adjustments = auto_deref_adjust_steps(&derefs); // FIXME: Handle call adjustments for Fn/FnMut self.write_expr_adj(*callee, adjustments); - res + if let Some((trait_, func)) = func { + let subst = TyBuilder::subst_for_def(self.db, trait_, None) + .push(callee_ty.clone()) + .push(TyBuilder::tuple_with(params.iter().cloned())) + .build(); + self.write_method_resolution(tgt_expr, func, subst.clone()); + } + (params, ret_ty) } None => (Vec::new(), self.err_ty()), // FIXME diagnostic }; @@ -587,7 +596,18 @@ impl<'a> InferenceContext<'a> { } Expr::Try { expr } => { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); - self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok()) + if let Some(trait_) = self.resolve_lang_trait(LangItem::Try) { + if let Some(func) = self.db.trait_data(trait_).method_by_name(&name!(branch)) { + let subst = TyBuilder::subst_for_def(self.db, trait_, None) + .push(inner_ty.clone()) + .build(); + self.write_method_resolution(tgt_expr, func, subst.clone()); + } + let try_output = self.resolve_output_on(trait_); + self.resolve_associated_type(inner_ty, try_output) + } else { + self.err_ty() + } } Expr::Cast { expr, type_ref } => { // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary) @@ -626,6 +646,7 @@ impl<'a> InferenceContext<'a> { Expr::UnaryOp { expr, op } => { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); let inner_ty = self.resolve_ty_shallow(&inner_ty); + // FIXME: Note down method resolution her match op { UnaryOp::Deref => { autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty()) @@ -735,7 +756,7 @@ impl<'a> InferenceContext<'a> { let base_ty = self.infer_expr_inner(*base, &Expectation::none()); let index_ty = self.infer_expr(*index, &Expectation::none()); - if let Some(index_trait) = self.resolve_ops_index() { + if let Some(index_trait) = self.resolve_lang_trait(LangItem::Index) { let canonicalized = self.canonicalize(base_ty.clone()); let receiver_adjustments = method_resolution::resolve_indexing_op( self.db, @@ -748,6 +769,15 @@ impl<'a> InferenceContext<'a> { adj.apply(&mut self.table, base_ty) }); self.write_expr_adj(*base, adj); + if let Some(func) = + self.db.trait_data(index_trait).method_by_name(&name!(index)) + { + let substs = TyBuilder::subst_for_def(self.db, index_trait, None) + .push(self_ty.clone()) + .push(index_ty.clone()) + .build(); + self.write_method_resolution(tgt_expr, func, substs.clone()); + } self.resolve_associated_type_with_params( self_ty, self.resolve_ops_index_output(), diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index e7ddd1591f..46ed3533c8 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -8,6 +8,7 @@ use chalk_ir::{ }; use chalk_solve::infer::ParameterEnaVariableExt; use ena::unify::UnifyKey; +use hir_def::{FunctionId, TraitId}; use hir_expand::name; use stdx::never; @@ -626,18 +627,26 @@ impl<'a> InferenceTable<'a> { } } - pub(crate) fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec, Ty)> { + pub(crate) fn callable_sig( + &mut self, + ty: &Ty, + num_args: usize, + ) -> Option<(Option<(TraitId, FunctionId)>, Vec, Ty)> { match ty.callable_sig(self.db) { - Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())), + Some(sig) => Some((None, sig.params().to_vec(), sig.ret().clone())), None => self.callable_sig_from_fn_trait(ty, num_args), } } - fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec, Ty)> { + fn callable_sig_from_fn_trait( + &mut self, + ty: &Ty, + num_args: usize, + ) -> Option<(Option<(TraitId, FunctionId)>, Vec, Ty)> { let krate = self.trait_env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; - let output_assoc_type = - self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; + let trait_data = self.db.trait_data(fn_once_trait); + let output_assoc_type = trait_data.associated_type_by_name(&name![Output])?; let mut arg_tys = vec![]; let arg_ty = TyBuilder::tuple(num_args) @@ -675,7 +684,11 @@ impl<'a> InferenceTable<'a> { if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() { self.register_obligation(obligation.goal); let return_ty = self.normalize_projection_ty(projection); - Some((arg_tys, return_ty)) + Some(( + Some(fn_once_trait).zip(trait_data.method_by_name(&name!(call_once))), + arg_tys, + return_ty, + )) } else { None } diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs index 42fb685abf..41c53701df 100644 --- a/crates/hir-ty/src/tests/method_resolution.rs +++ b/crates/hir-ty/src/tests/method_resolution.rs @@ -986,14 +986,13 @@ fn main() { } #[test] -fn method_resolution_encountering_fn_type() { +fn explicit_fn_once_call_fn_item() { check_types( r#" -//- /main.rs +//- minicore: fn fn foo() {} -trait FnOnce { fn call(self); } -fn test() { foo.call(); } - //^^^^^^^^^^ {unknown} +fn test() { foo.call_once(); } + //^^^^^^^^^^^^^^^ () "#, ); } diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 88670364bd..015085bde4 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -1757,25 +1757,19 @@ fn test() { fn fn_trait() { check_infer_with_mismatches( r#" -trait FnOnce { - type Output; - - fn call_once(self, args: Args) -> >::Output; -} +//- minicore: fn fn test u128>(f: F) { f.call_once((1, 2)); }"#, expect![[r#" - 56..60 'self': Self - 62..66 'args': Args - 149..150 'f': F - 155..183 '{ ...2)); }': () - 161..162 'f': F - 161..180 'f.call...1, 2))': u128 - 173..179 '(1, 2)': (u32, u64) - 174..175 '1': u32 - 177..178 '2': u64 + 38..39 'f': F + 44..72 '{ ...2)); }': () + 50..51 'f': F + 50..69 'f.call...1, 2))': u128 + 62..68 '(1, 2)': (u32, u64) + 63..64 '1': u32 + 66..67 '2': u64 "#]], ); } @@ -1784,12 +1778,7 @@ fn test u128>(f: F) { fn fn_ptr_and_item() { check_infer_with_mismatches( r#" -#[lang="fn_once"] -trait FnOnce { - type Output; - - fn call_once(self, args: Args) -> Self::Output; -} +//- minicore: fn trait Foo { fn foo(&self) -> T; @@ -1815,27 +1804,25 @@ fn test() { opt.map(f); }"#, expect![[r#" - 74..78 'self': Self - 80..84 'args': Args - 139..143 'self': &Self - 243..247 'self': &Bar - 260..271 '{ loop {} }': (A1, R) - 262..269 'loop {}': ! - 267..269 '{}': () - 355..359 'self': Opt - 361..362 'f': F - 377..388 '{ loop {} }': Opt - 379..386 'loop {}': ! - 384..386 '{}': () - 402..518 '{ ...(f); }': () - 412..415 'bar': Bar u32> - 441..444 'bar': Bar u32> - 441..450 'bar.foo()': (u8, u32) - 461..464 'opt': Opt - 483..484 'f': fn(u8) -> u32 - 505..508 'opt': Opt - 505..515 'opt.map(f)': Opt - 513..514 'f': fn(u8) -> u32 + 28..32 'self': &Self + 132..136 'self': &Bar + 149..160 '{ loop {} }': (A1, R) + 151..158 'loop {}': ! + 156..158 '{}': () + 244..248 'self': Opt + 250..251 'f': F + 266..277 '{ loop {} }': Opt + 268..275 'loop {}': ! + 273..275 '{}': () + 291..407 '{ ...(f); }': () + 301..304 'bar': Bar u32> + 330..333 'bar': Bar u32> + 330..339 'bar.foo()': (u8, u32) + 350..353 'opt': Opt + 372..373 'f': fn(u8) -> u32 + 394..397 'opt': Opt + 394..404 'opt.map(f)': Opt + 402..403 'f': fn(u8) -> u32 "#]], ); } @@ -2308,10 +2295,8 @@ fn unselected_projection_in_trait_env_no_cycle() { // this is not a cycle check_types( r#" -//- /main.rs -trait Index { - type Output; -} +//- minicore: index +use core::ops::Index; type Key = ::Key; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 4415bef4bb..39589bf8bc 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2411,7 +2411,7 @@ impl Local { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct DeriveHelper { pub(crate) derive: MacroId, - pub(crate) idx: usize, + pub(crate) idx: u32, } impl DeriveHelper { @@ -2421,15 +2421,18 @@ impl DeriveHelper { pub fn name(&self, db: &dyn HirDatabase) -> Name { match self.derive { - MacroId::Macro2Id(it) => { - db.macro2_data(it).helpers.as_deref().and_then(|it| it.get(self.idx)).cloned() - } + MacroId::Macro2Id(it) => db + .macro2_data(it) + .helpers + .as_deref() + .and_then(|it| it.get(self.idx as usize)) + .cloned(), MacroId::MacroRulesId(_) => None, MacroId::ProcMacroId(proc_macro) => db .proc_macro_data(proc_macro) .helpers .as_deref() - .and_then(|it| it.get(self.idx)) + .and_then(|it| it.get(self.idx as usize)) .cloned(), } .unwrap_or_else(|| Name::missing()) @@ -2440,7 +2443,7 @@ impl DeriveHelper { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct BuiltinAttr { krate: Option, - idx: usize, + idx: u32, } impl BuiltinAttr { @@ -2449,7 +2452,8 @@ impl BuiltinAttr { if let builtin @ Some(_) = Self::builtin(name) { return builtin; } - let idx = db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)?; + let idx = + db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)? as u32; Some(BuiltinAttr { krate: Some(krate.id), idx }) } @@ -2457,21 +2461,21 @@ impl BuiltinAttr { hir_def::builtin_attr::INERT_ATTRIBUTES .iter() .position(|tool| tool.name == name) - .map(|idx| BuiltinAttr { krate: None, idx }) + .map(|idx| BuiltinAttr { krate: None, idx: idx as u32 }) } pub fn name(&self, db: &dyn HirDatabase) -> SmolStr { // FIXME: Return a `Name` here match self.krate { - Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx].clone(), - None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].name), + Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(), + None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx as usize].name), } } pub fn template(&self, _: &dyn HirDatabase) -> Option { match self.krate { Some(_) => None, - None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].template), + None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx as usize].template), } } } @@ -2479,7 +2483,7 @@ impl BuiltinAttr { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct ToolModule { krate: Option, - idx: usize, + idx: u32, } impl ToolModule { @@ -2488,7 +2492,8 @@ impl ToolModule { if let builtin @ Some(_) = Self::builtin(name) { return builtin; } - let idx = db.crate_def_map(krate.id).registered_tools().iter().position(|it| it == name)?; + let idx = + db.crate_def_map(krate.id).registered_tools().iter().position(|it| it == name)? as u32; Some(ToolModule { krate: Some(krate.id), idx }) } @@ -2496,14 +2501,14 @@ impl ToolModule { hir_def::builtin_attr::TOOL_MODULES .iter() .position(|&tool| tool == name) - .map(|idx| ToolModule { krate: None, idx }) + .map(|idx| ToolModule { krate: None, idx: idx as u32 }) } pub fn name(&self, db: &dyn HirDatabase) -> SmolStr { // FIXME: Return a `Name` here match self.krate { - Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx].clone(), - None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx]), + Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx as usize].clone(), + None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx as usize]), } } } @@ -2831,7 +2836,7 @@ impl Impl { } } -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef { env: Arc, trait_ref: hir_ty::TraitRef, diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 5e0c9933a7..3b39e9fa91 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -628,7 +628,7 @@ impl SourceAnalyzer { { return Some(PathResolution::DeriveHelper(DeriveHelper { derive: *macro_id, - idx, + idx: idx as u32, })); } } diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index 6c13c03972..ed7f04fd8e 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -34,8 +34,8 @@ pub enum Definition { TypeAlias(TypeAlias), BuiltinType(BuiltinType), SelfType(Impl), - Local(Local), GenericParam(GenericParam), + Local(Local), Label(Label), DeriveHelper(DeriveHelper), BuiltinAttr(BuiltinAttr), diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs index 971168aa28..da44d95297 100644 --- a/crates/ide/src/inlay_hints/bind_pat.rs +++ b/crates/ide/src/inlay_hints/bind_pat.rs @@ -325,7 +325,7 @@ fn main(a: SliceIter<'_, Container>) { file_id: FileId( 1, ), - range: 2248..2256, + range: 2611..2619, }, ), tooltip: "", @@ -338,7 +338,7 @@ fn main(a: SliceIter<'_, Container>) { file_id: FileId( 1, ), - range: 2248..2256, + range: 2611..2619, }, ), tooltip: "", diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index b522450310..222ee59be8 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -435,7 +435,7 @@ fn main() { file_id: FileId( 1, ), - range: 2248..2256, + range: 2611..2619, }, ), tooltip: "", @@ -455,7 +455,7 @@ fn main() { file_id: FileId( 1, ), - range: 2248..2256, + range: 2611..2619, }, ), tooltip: "", @@ -475,7 +475,7 @@ fn main() { file_id: FileId( 1, ), - range: 2248..2256, + range: 2611..2619, }, ), tooltip: "", diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 5634bafd06..3b033e1aae 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -106,6 +106,11 @@ pub mod marker { impl Copy for &T {} } // endregion:copy + + // region:fn + #[lang = "tuple_trait"] + pub trait Tuple {} + // endregion:fn } // region:default @@ -347,19 +352,26 @@ pub mod ops { // region:fn mod function { + use crate::marker::Tuple; + #[lang = "fn"] #[fundamental] - pub trait Fn: FnMut {} + pub trait Fn: FnMut { + extern "rust-call" fn call(&self, args: Args) -> Self::Output; + } #[lang = "fn_mut"] #[fundamental] - pub trait FnMut: FnOnce {} + pub trait FnMut: FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; + } #[lang = "fn_once"] #[fundamental] - pub trait FnOnce { + pub trait FnOnce { #[lang = "fn_once_output"] type Output; + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } } pub use self::function::{Fn, FnMut, FnOnce};