From ccd1b0800a5de5e046e6e9a4b6f49030c1ce3639 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 28 Nov 2019 12:50:26 +0300 Subject: Rename Source -> InFile --- crates/ra_hir_ty/src/diagnostics.rs | 14 +++++++------- crates/ra_hir_ty/src/tests.rs | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 4a13fac23..5054189cc 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs @@ -2,7 +2,7 @@ use std::any::Any; -use hir_expand::{db::AstDatabase, name::Name, HirFileId, Source}; +use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; pub use hir_def::diagnostics::UnresolvedModule; @@ -19,8 +19,8 @@ impl Diagnostic for NoSuchField { "no such field".to_string() } - fn source(&self) -> Source { - Source { file_id: self.file, value: self.field.into() } + fn source(&self) -> InFile { + InFile { file_id: self.file, value: self.field.into() } } fn as_any(&self) -> &(dyn Any + Send + 'static) { @@ -44,8 +44,8 @@ impl Diagnostic for MissingFields { } message } - fn source(&self) -> Source { - Source { file_id: self.file, value: self.field_list.into() } + fn source(&self) -> InFile { + InFile { file_id: self.file, value: self.field_list.into() } } fn as_any(&self) -> &(dyn Any + Send + 'static) { self @@ -72,8 +72,8 @@ impl Diagnostic for MissingOkInTailExpr { fn message(&self) -> String { "wrap return expression in Ok".to_string() } - fn source(&self) -> Source { - Source { file_id: self.file, value: self.expr.into() } + fn source(&self) -> InFile { + InFile { file_id: self.file, value: self.expr.into() } } fn as_any(&self) -> &(dyn Any + Send + 'static) { self diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index c8461b447..abbc1546c 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -8,7 +8,7 @@ use hir_def::{ body::BodySourceMap, db::DefDatabase, nameres::CrateDefMap, AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, }; -use hir_expand::Source; +use hir_expand::InFile; use insta::assert_snapshot; use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; use ra_syntax::{ @@ -4680,7 +4680,7 @@ fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { for decl in crate_def_map[module.local_id].scope.declarations() { if let ModuleDefId::FunctionId(func) = decl { let (_body, source_map) = db.body_with_source_map(func.into()); - if let Some(expr_id) = source_map.node_expr(Source::new(pos.file_id.into(), &expr)) { + if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { let infer = db.infer(func.into()); let ty = &infer[expr_id]; return ty.display(db).to_string(); -- cgit v1.2.3 From 8f1f5a783a3ffd0afbf5b1fdf22ff9caf7fda928 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 28 Nov 2019 18:05:28 +0300 Subject: Move source-related traits to a separate module --- crates/ra_hir_ty/src/infer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 1e9f4b208..f6283ab6d 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -693,7 +693,7 @@ impl Expectation { } mod diagnostics { - use hir_def::{expr::ExprId, FunctionId, HasSource, Lookup}; + use hir_def::{expr::ExprId, src::HasSource, FunctionId, Lookup}; use hir_expand::diagnostics::DiagnosticSink; use crate::{db::HirDatabase, diagnostics::NoSuchField}; -- cgit v1.2.3 From 4992d2bf79e9da6db759eb8e1715f90f31ec7eb9 Mon Sep 17 00:00:00 2001 From: oxalica Date: Fri, 29 Nov 2019 03:10:16 +0800 Subject: Infer range types --- crates/ra_hir_ty/src/infer.rs | 36 +++++++++++++++++++++++++++ crates/ra_hir_ty/src/infer/expr.rs | 41 +++++++++++++++++++++++++++++++ crates/ra_hir_ty/src/tests.rs | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index f6283ab6d..fe259371f 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -577,6 +577,42 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; Some(struct_.into()) } + + fn resolve_range_full(&self) -> Option { + let path = known::std_ops_range_full(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } + + fn resolve_range(&self) -> Option { + let path = known::std_ops_range(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } + + fn resolve_range_inclusive(&self) -> Option { + let path = known::std_ops_range_inclusive(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } + + fn resolve_range_from(&self) -> Option { + let path = known::std_ops_range_from(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } + + fn resolve_range_to(&self) -> Option { + let path = known::std_ops_range_to(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } + + fn resolve_range_to_inclusive(&self) -> Option { + let path = known::std_ops_range_to_inclusive(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } } /// The ID of a type variable. diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 2f9ca4bbb..a00aa426a 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -415,6 +415,47 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } _ => Ty::Unknown, }, + Expr::RangeFull => match self.resolve_range_full() { + Some(adt) => Ty::simple(TypeCtor::Adt(adt)), + None => Ty::Unknown, + }, + Expr::Range { lhs, rhs } => { + let lhs_ty = self.infer_expr(*lhs, &Expectation::none()); + let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(lhs_ty)); + match self.resolve_range() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), rhs_ty), + None => Ty::Unknown, + } + } + Expr::RangeInclusive { lhs, rhs } => { + let lhs_ty = self.infer_expr(*lhs, &Expectation::none()); + let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(lhs_ty)); + match self.resolve_range_inclusive() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), rhs_ty), + None => Ty::Unknown, + } + } + Expr::RangeFrom { lhs } => { + let ty = self.infer_expr(*lhs, &Expectation::none()); + match self.resolve_range_from() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + } + } + Expr::RangeTo { rhs } => { + let ty = self.infer_expr(*rhs, &Expectation::none()); + match self.resolve_range_to() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + } + } + Expr::RangeToInclusive { rhs } => { + let ty = self.infer_expr(*rhs, &Expectation::none()); + match self.resolve_range_to_inclusive() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + } + } Expr::Index { base, index } => { let _base_ty = self.infer_expr(*base, &Expectation::none()); let _index_ty = self.infer_expr(*index, &Expectation::none()); diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index abbc1546c..4ba87e667 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -221,6 +221,56 @@ mod collections { assert_eq!("&str", type_at_pos(&db, pos)); } +#[test] +fn infer_ranges() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std +fn test() { + let a = ..; + let b = 1..; + let c = ..2u32; + let d = 1..2usize; + let e = ..=10; + let f = 'a'..='z'; + + let t = (a, b, c, d, e, f); + t<|>; +} + +//- /std.rs crate:std +#[prelude_import] use prelude::*; +mod prelude {} + +pub mod ops { + pub struct Range { + pub start: Idx, + pub end: Idx, + } + pub struct RangeFrom { + pub start: Idx, + } + struct RangeFull; + pub struct RangeInclusive { + start: Idx, + end: Idx, + is_empty: u8, + } + pub struct RangeTo { + pub end: Idx, + } + pub struct RangeToInclusive { + pub end: Idx, + } +} +"#, + ); + assert_eq!( + "(RangeFull, RangeFrom, RangeTo, Range, RangeToInclusive, RangeInclusive)", + type_at_pos(&db, pos), + ); +} + #[test] fn infer_while_let() { let (db, pos) = TestDB::with_position( -- cgit v1.2.3 From 2cb684bbce1c487b2efb5a8154afe66e4907ceac Mon Sep 17 00:00:00 2001 From: oxalica Date: Fri, 29 Nov 2019 14:49:12 +0800 Subject: Reduce variants of Expr --- crates/ra_hir_ty/src/infer/expr.rs | 76 +++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 39 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index a00aa426a..4014f4732 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -12,6 +12,7 @@ use hir_def::{ AdtId, ContainerId, Lookup, StructFieldId, }; use hir_expand::name::{self, Name}; +use ra_syntax::ast::RangeOp; use crate::{ autoderef, db::HirDatabase, method_resolution, op, traits::InEnvironment, utils::variant_data, @@ -415,45 +416,42 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } _ => Ty::Unknown, }, - Expr::RangeFull => match self.resolve_range_full() { - Some(adt) => Ty::simple(TypeCtor::Adt(adt)), - None => Ty::Unknown, - }, - Expr::Range { lhs, rhs } => { - let lhs_ty = self.infer_expr(*lhs, &Expectation::none()); - let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(lhs_ty)); - match self.resolve_range() { - Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), rhs_ty), - None => Ty::Unknown, - } - } - Expr::RangeInclusive { lhs, rhs } => { - let lhs_ty = self.infer_expr(*lhs, &Expectation::none()); - let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(lhs_ty)); - match self.resolve_range_inclusive() { - Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), rhs_ty), - None => Ty::Unknown, - } - } - Expr::RangeFrom { lhs } => { - let ty = self.infer_expr(*lhs, &Expectation::none()); - match self.resolve_range_from() { - Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), - None => Ty::Unknown, - } - } - Expr::RangeTo { rhs } => { - let ty = self.infer_expr(*rhs, &Expectation::none()); - match self.resolve_range_to() { - Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), - None => Ty::Unknown, - } - } - Expr::RangeToInclusive { rhs } => { - let ty = self.infer_expr(*rhs, &Expectation::none()); - match self.resolve_range_to_inclusive() { - Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), - None => Ty::Unknown, + Expr::Range { lhs, rhs, range_type } => { + let lhs_ty = lhs.map(|e| self.infer_expr(e, &Expectation::none())); + let rhs_expect = lhs_ty + .as_ref() + .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone())); + let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect)); + match (range_type, lhs_ty, rhs_ty) { + (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { + Some(adt) => Ty::simple(TypeCtor::Adt(adt)), + None => Ty::Unknown, + }, + (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + }, + (RangeOp::Inclusive, None, Some(ty)) => { + match self.resolve_range_to_inclusive() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + } + } + (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + }, + (RangeOp::Inclusive, Some(_), Some(ty)) => { + match self.resolve_range_inclusive() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + } + } + (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + }, + (RangeOp::Inclusive, _, None) => Ty::Unknown, } } Expr::Index { base, index } => { -- cgit v1.2.3 From cf6809645e2327e20edd30eb535d4f06fa116b5c Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 30 Nov 2019 12:35:37 +0100 Subject: Handle cycles in impl types better - impl Trait for S is allowed - impl Trait for S is an invalid cycle, but we can add cycle recovery for it in Salsa now --- crates/ra_hir_ty/src/db.rs | 10 +++++--- crates/ra_hir_ty/src/infer/coerce.rs | 7 ++---- crates/ra_hir_ty/src/infer/path.rs | 2 +- crates/ra_hir_ty/src/lib.rs | 15 ----------- crates/ra_hir_ty/src/lower.rs | 35 +++++++++++++++----------- crates/ra_hir_ty/src/method_resolution.rs | 9 ++++--- crates/ra_hir_ty/src/tests.rs | 42 +++++++++++++++++++++++++++++++ crates/ra_hir_ty/src/traits/chalk.rs | 15 +++-------- 8 files changed, 82 insertions(+), 53 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index 9ce154593..6ecc0b096 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs @@ -11,7 +11,7 @@ use ra_db::{salsa, CrateId}; use crate::{ method_resolution::CrateImplBlocks, traits::{AssocTyValue, Impl}, - CallableDef, FnSig, GenericPredicate, ImplTy, InferenceResult, Substs, Ty, TyDefId, TypeCtor, + CallableDef, FnSig, GenericPredicate, InferenceResult, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, }; @@ -27,8 +27,12 @@ pub trait HirDatabase: DefDatabase { #[salsa::invoke(crate::lower::value_ty_query)] fn value_ty(&self, def: ValueTyDefId) -> Ty; - #[salsa::invoke(crate::lower::impl_ty_query)] - fn impl_ty(&self, def: ImplId) -> ImplTy; + #[salsa::invoke(crate::lower::impl_self_ty_query)] + #[salsa::cycle(crate::lower::impl_self_ty_recover)] + fn impl_self_ty(&self, def: ImplId) -> Ty; + + #[salsa::invoke(crate::lower::impl_trait_query)] + fn impl_trait(&self, def: ImplId) -> Option; #[salsa::invoke(crate::lower::field_types_query)] fn field_types(&self, var: VariantId) -> Arc>; diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 719a0f395..064993d34 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs @@ -8,7 +8,7 @@ use hir_def::{lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutabilit use rustc_hash::FxHashMap; use test_utils::tested_by; -use crate::{autoderef, db::HirDatabase, ImplTy, Substs, Ty, TypeCtor, TypeWalk}; +use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk}; use super::{InEnvironment, InferTy, InferenceContext, TypeVarValue}; @@ -54,10 +54,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { impls .iter() .filter_map(|&impl_id| { - let trait_ref = match db.impl_ty(impl_id) { - ImplTy::TraitRef(it) => it, - ImplTy::Inherent(_) => return None, - }; + let trait_ref = db.impl_trait(impl_id)?; // `CoerseUnsized` has one generic parameter for the target type. let cur_from_ty = trait_ref.substs.0.get(0)?; diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 14be66836..bbf146418 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -244,7 +244,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ContainerId::ImplId(it) => it, _ => return None, }; - let self_ty = self.db.impl_ty(impl_id).self_type().clone(); + let self_ty = self.db.impl_self_ty(impl_id).clone(); let self_ty_substs = self_ty.substs()?; let actual_substs = actual_def_ty.substs()?; diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index b45c8f82f..3c1f738df 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -486,21 +486,6 @@ impl TypeWalk for TraitRef { } } -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum ImplTy { - Inherent(Ty), - TraitRef(TraitRef), -} - -impl ImplTy { - pub(crate) fn self_type(&self) -> &Ty { - match self { - ImplTy::Inherent(it) => it, - ImplTy::TraitRef(tr) => &tr.substs[0], - } - } -} - /// Like `generics::WherePredicate`, but with resolved types: A condition on the /// parameters of a generic item. #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 091c60f4f..a646406f1 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -27,8 +27,8 @@ use crate::{ all_super_traits, associated_type_by_name_including_super_traits, make_mut_slice, variant_data, }, - FnSig, GenericPredicate, ImplTy, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, - TraitRef, Ty, TypeCtor, TypeWalk, + FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, + Ty, TypeCtor, TypeWalk, }; impl Ty { @@ -179,7 +179,7 @@ impl Ty { let name = resolved_segment.name.clone(); Ty::Param { idx, name } } - TypeNs::SelfType(impl_id) => db.impl_ty(impl_id).self_type().clone(), + TypeNs::SelfType(impl_id) => db.impl_self_ty(impl_id).clone(), TypeNs::AdtSelfType(adt) => db.ty(adt.into()), TypeNs::AdtId(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()), @@ -743,17 +743,24 @@ pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty { } } -pub(crate) fn impl_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> ImplTy { +pub(crate) fn impl_self_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> Ty { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db); - let self_ty = Ty::from_hir(db, &resolver, &impl_data.target_type); - match impl_data.target_trait.as_ref() { - Some(trait_ref) => { - match TraitRef::from_hir(db, &resolver, trait_ref, Some(self_ty.clone())) { - Some(it) => ImplTy::TraitRef(it), - None => ImplTy::Inherent(self_ty), - } - } - None => ImplTy::Inherent(self_ty), - } + Ty::from_hir(db, &resolver, &impl_data.target_type) +} + +pub(crate) fn impl_self_ty_recover( + _db: &impl HirDatabase, + _cycle: &[String], + _impl_id: &ImplId, +) -> Ty { + Ty::Unknown +} + +pub(crate) fn impl_trait_query(db: &impl HirDatabase, impl_id: ImplId) -> Option { + let impl_data = db.impl_data(impl_id); + let resolver = impl_id.resolver(db); + let self_ty = db.impl_self_ty(impl_id); + let target_trait = impl_data.target_trait.as_ref()?; + TraitRef::from_hir(db, &resolver, target_trait, Some(self_ty.clone())) } diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index ee1936b0e..2bded3dbd 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -19,7 +19,7 @@ use crate::{ db::HirDatabase, primitive::{FloatBitness, Uncertain}, utils::all_super_traits, - Canonical, ImplTy, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, + Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, }; /// This is used as a key for indexing impls. @@ -58,11 +58,12 @@ impl CrateImplBlocks { let crate_def_map = db.crate_def_map(krate); for (_module_id, module_data) in crate_def_map.modules.iter() { for &impl_id in module_data.impls.iter() { - match db.impl_ty(impl_id) { - ImplTy::TraitRef(tr) => { + match db.impl_trait(impl_id) { + Some(tr) => { res.impls_by_trait.entry(tr.trait_).or_default().push(impl_id); } - ImplTy::Inherent(self_ty) => { + None => { + let self_ty = db.impl_self_ty(impl_id); if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty) { res.impls.entry(self_ty_fp).or_default().push(impl_id); } diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 4ba87e667..b72f0f279 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -4675,6 +4675,48 @@ fn test() where T::Item: Trait2, T: Trait, U: Trait<()> { assert_eq!(t, "u32"); } +#[test] +fn trait_impl_self_ty() { + let t = type_at( + r#" +//- /main.rs +trait Trait { + fn foo(&self); +} + +struct S; + +impl Trait for S {} + +fn test() { + S.foo()<|>; +} +"#, + ); + assert_eq!(t, "()"); +} + +#[test] +fn trait_impl_self_ty_cycle() { + let t = type_at( + r#" +//- /main.rs +trait Trait { + fn foo(&self); +} + +struct S; + +impl Trait for S {} + +fn test() { + S.foo()<|>; +} +"#, + ); + assert_eq!(t, "{unknown}"); +} + #[test] // FIXME this is currently a Salsa panic; it would be nicer if it just returned // in Unknown, and we should be able to do that once Salsa allows us to handle diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 35de37e6b..104346ada 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -20,8 +20,8 @@ use ra_db::salsa::{InternId, InternKey}; use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; use crate::{ - db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ImplTy, ProjectionTy, - Substs, TraitRef, Ty, TypeCtor, TypeWalk, + db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ProjectionTy, Substs, + TraitRef, Ty, TypeCtor, TypeWalk, }; /// This represents a trait whose name we could not resolve. @@ -630,10 +630,7 @@ fn impl_block_datum( chalk_id: chalk_ir::ImplId, impl_id: ImplId, ) -> Option>> { - let trait_ref = match db.impl_ty(impl_id) { - ImplTy::TraitRef(it) => it, - ImplTy::Inherent(_) => return None, - }; + let trait_ref = db.impl_trait(impl_id)?; let impl_data = db.impl_data(impl_id); let generic_params = db.generic_params(impl_id.into()); @@ -787,11 +784,7 @@ fn type_alias_associated_ty_value( _ => panic!("assoc ty value should be in impl"), }; - let trait_ref = match db.impl_ty(impl_id) { - ImplTy::TraitRef(it) => it, - // we don't return any assoc ty values if the impl'd trait can't be resolved - ImplTy::Inherent(_) => panic!("assoc ty value should not exist"), - }; + let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist"); // we don't return any assoc ty values if the impl'd trait can't be resolved let assoc_ty = db .trait_data(trait_ref.trait_) -- cgit v1.2.3 From 3ca40f7c08718a44c6d08d2cbe060244340e7157 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 30 Nov 2019 12:39:21 +0100 Subject: Add cycle recovery for generic predicates --- crates/ra_hir_ty/src/db.rs | 1 + crates/ra_hir_ty/src/lower.rs | 9 +++++++++ crates/ra_hir_ty/src/tests.rs | 8 -------- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index 6ecc0b096..8e461e359 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs @@ -41,6 +41,7 @@ pub trait HirDatabase: DefDatabase { fn callable_item_signature(&self, def: CallableDef) -> FnSig; #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] + #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] fn generic_predicates_for_param( &self, def: GenericDefId, diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index a646406f1..c6ee75c7a 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -532,6 +532,15 @@ pub(crate) fn generic_predicates_for_param_query( .collect() } +pub(crate) fn generic_predicates_for_param_recover( + _db: &impl HirDatabase, + _cycle: &[String], + _def: &GenericDefId, + _param_idx: &u32, +) -> Arc<[GenericPredicate]> { + Arc::new([]) +} + impl TraitEnvironment { pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc { let predicates = resolver diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index b72f0f279..552eb8f75 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -4718,10 +4718,6 @@ fn test() { } #[test] -// FIXME this is currently a Salsa panic; it would be nicer if it just returned -// in Unknown, and we should be able to do that once Salsa allows us to handle -// the cycle. But at least it doesn't overflow for now. -#[should_panic] fn unselected_projection_in_trait_env_cycle_1() { let t = type_at( r#" @@ -4742,10 +4738,6 @@ fn test() where T: Trait2 { } #[test] -// FIXME this is currently a Salsa panic; it would be nicer if it just returned -// in Unknown, and we should be able to do that once Salsa allows us to handle -// the cycle. But at least it doesn't overflow for now. -#[should_panic] fn unselected_projection_in_trait_env_cycle_2() { let t = type_at( r#" -- cgit v1.2.3 From 1c622e9fed97de7711da7b5bffec0fa4b19d7500 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 30 Nov 2019 12:48:51 +0100 Subject: Add cycle recovery for type aliases --- crates/ra_hir_ty/src/db.rs | 1 + crates/ra_hir_ty/src/lower.rs | 5 +++++ crates/ra_hir_ty/src/tests.rs | 6 ++++-- 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index 8e461e359..222a36a9f 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs @@ -22,6 +22,7 @@ pub trait HirDatabase: DefDatabase { fn infer(&self, def: DefWithBodyId) -> Arc; #[salsa::invoke(crate::lower::ty_query)] + #[salsa::cycle(crate::lower::ty_recover)] fn ty(&self, def: TyDefId) -> Ty; #[salsa::invoke(crate::lower::value_ty_query)] diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index c6ee75c7a..32569ac66 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -742,6 +742,11 @@ pub(crate) fn ty_query(db: &impl HirDatabase, def: TyDefId) -> Ty { TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), } } + +pub(crate) fn ty_recover(_db: &impl HirDatabase, _cycle: &[String], _def: &TyDefId) -> Ty { + Ty::Unknown +} + pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty { match def { ValueTyDefId::FunctionId(it) => type_for_fn(db, it), diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 552eb8f75..c856d6afd 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -2154,7 +2154,6 @@ fn test(x: Foo, y: Bar<&str>, z: Baz) { } #[test] -#[should_panic] // we currently can't handle this fn recursive_type_alias() { assert_snapshot!( infer(r#" @@ -2163,7 +2162,10 @@ type Foo = Foo; type Bar = A; fn test(x: Foo) {} "#), - @"" + @r###" + [59; 60) 'x': {unknown} + [67; 69) '{}': () + "### ) } -- cgit v1.2.3 From bb601e7eafa00e471a5306ac920f0be6c809aab0 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 30 Nov 2019 23:29:21 +0800 Subject: Add BuiltinShadowMode --- crates/ra_hir_ty/src/tests.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index abbc1546c..3766ab981 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -3641,6 +3641,42 @@ fn main() { assert_eq!(t, "Foo"); } +#[test] +fn not_shadowing_primitive_by_module() { + let t = type_at( + r#" +//- /str.rs +fn foo() {} + +//- /main.rs +mod str; +fn foo() -> &'static str { "" } + +fn main() { + foo()<|>; +}"#, + ); + assert_eq!(t, "&str"); +} + +#[test] +fn not_shadowing_module_by_primitive() { + let t = type_at( + r#" +//- /str.rs +fn foo() -> u32 {0} + +//- /main.rs +mod str; +fn foo() -> &'static str { "" } + +fn main() { + str::foo()<|>; +}"#, + ); + assert_eq!(t, "u32"); +} + #[test] fn deref_trait() { let t = type_at( -- cgit v1.2.3 From cbf262a1bc72f10dc93a4993da0012d3b0abb56f Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 2 Nov 2019 15:18:26 +0100 Subject: Change order of calls to get method candidate order correct --- crates/ra_hir_ty/src/method_resolution.rs | 152 ++++++++++++++++++++++-------- crates/ra_hir_ty/src/tests.rs | 2 - 2 files changed, 115 insertions(+), 39 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 2bded3dbd..fbb932a3e 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -176,7 +176,6 @@ pub fn iterate_method_candidates( mode: LookupMode, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { - let krate = resolver.krate()?; match mode { LookupMode::MethodCall => { // For method calls, rust first does any number of autoderef, and then one @@ -189,57 +188,125 @@ pub fn iterate_method_candidates( // rustc does an autoderef and then autoref again). let environment = TraitEnvironment::lower(db, resolver); let ty = InEnvironment { value: ty.clone(), environment }; - for derefed_ty in autoderef::autoderef(db, resolver.krate(), ty) { - if let Some(result) = - iterate_inherent_methods(&derefed_ty, db, name, mode, krate, &mut callback) - { - return Some(result); - } - if let Some(result) = iterate_trait_method_candidates( - &derefed_ty, + let krate = resolver.krate()?; + + // We have to be careful about the order of operations here. + // Consider the case where we're resolving `x.clone()` where `x: + // &Vec<_>`. This resolves to the clone method with self type + // `Vec<_>`, *not* `&_`. I.e. we need to consider methods where the + // receiver type exactly matches before cases where we have to do + // autoref. But in the autoderef steps, the `&_` self type comes up + // *before* the `Vec<_>` self type. + // + // On the other hand, we don't want to just pick any by-value method + // before any by-autoref method; it's just that we need to consider + // the methods by autoderef order of *receiver types*, not *self + // types*. + + let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty.clone()).collect(); + for i in 0..deref_chain.len() { + if let Some(result) = iterate_method_candidates_autoref( + &deref_chain[i..], db, resolver, name, - mode, &mut callback, ) { return Some(result); } } + None } LookupMode::Path => { // No autoderef for path lookups - if let Some(result) = - iterate_inherent_methods(&ty, db, name, mode, krate.into(), &mut callback) - { - return Some(result); - } - if let Some(result) = - iterate_trait_method_candidates(&ty, db, resolver, name, mode, &mut callback) - { - return Some(result); - } + iterate_method_candidates_inner(&ty, db, resolver, name, None, &mut callback) + } + } +} + +fn iterate_method_candidates_autoref( + deref_chain: &[Canonical], + db: &impl HirDatabase, + resolver: &Resolver, + name: Option<&Name>, + mut callback: impl FnMut(&Ty, AssocItemId) -> Option, +) -> Option { + if let Some(result) = iterate_method_candidates_by_receiver(&deref_chain[0], &deref_chain[1..], db, resolver, name, &mut callback) { + return Some(result); + } + let refed = Canonical { + num_vars: deref_chain[0].num_vars, + value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), + }; + if let Some(result) = iterate_method_candidates_by_receiver(&refed, deref_chain, db, resolver, name, &mut callback) { + return Some(result); + } + let ref_muted = Canonical { + num_vars: deref_chain[0].num_vars, + value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), + }; + if let Some(result) = iterate_method_candidates_by_receiver(&ref_muted, deref_chain, db, resolver, name, &mut callback) { + return Some(result); + } + None +} + +fn iterate_method_candidates_by_receiver( + receiver_ty: &Canonical, + deref_chain: &[Canonical], + db: &impl HirDatabase, + resolver: &Resolver, + name: Option<&Name>, + mut callback: impl FnMut(&Ty, AssocItemId) -> Option, +) -> Option { + // TODO: do we need to do the whole loop for inherents before traits? + // We're looking for methods with *receiver* type receiver_ty. These could + // be found in any of the derefs of receiver_ty, so we have to go through + // that. + for self_ty in std::iter::once(receiver_ty).chain(deref_chain) { + if let Some(result) = iterate_method_candidates_inner(self_ty, db, resolver, name, Some(receiver_ty), &mut callback) { + return Some(result); } } None } +fn iterate_method_candidates_inner( + self_ty: &Canonical, + db: &impl HirDatabase, + resolver: &Resolver, + name: Option<&Name>, + receiver_ty: Option<&Canonical>, + mut callback: impl FnMut(&Ty, AssocItemId) -> Option, +) -> Option { + let krate = resolver.krate()?; + if let Some(result) = iterate_inherent_methods(self_ty, db, name, receiver_ty, krate, &mut callback) { + return Some(result); + } + if let Some(result) = + iterate_trait_method_candidates(self_ty, db, resolver, name, receiver_ty, &mut callback) + { + return Some(result); + } + None +} + fn iterate_trait_method_candidates( - ty: &Canonical, + self_ty: &Canonical, db: &impl HirDatabase, resolver: &Resolver, name: Option<&Name>, - mode: LookupMode, + receiver_ty: Option<&Canonical>, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { let krate = resolver.krate()?; // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) let env = TraitEnvironment::lower(db, resolver); // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope - let inherent_trait = ty.value.inherent_trait().into_iter(); + let inherent_trait = self_ty.value.inherent_trait().into_iter(); // if we have `T: Trait` in the param env, the trait doesn't need to be in scope let traits_from_env = env - .trait_predicates_for_self_ty(&ty.value) + .trait_predicates_for_self_ty(&self_ty.value) .map(|tr| tr.trait_) .flat_map(|t| all_super_traits(db, t)); let traits = @@ -252,17 +319,17 @@ fn iterate_trait_method_candidates( // iteration let mut known_implemented = false; for (_name, item) in data.items.iter() { - if !is_valid_candidate(db, name, mode, (*item).into()) { + if !is_valid_candidate(db, name, receiver_ty, (*item).into(), self_ty) { continue; } if !known_implemented { - let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); + let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone()); if db.trait_solve(krate.into(), goal).is_none() { continue 'traits; } } known_implemented = true; - if let Some(result) = callback(&ty.value, (*item).into()) { + if let Some(result) = callback(&self_ty.value, (*item).into()) { return Some(result); } } @@ -271,22 +338,22 @@ fn iterate_trait_method_candidates( } fn iterate_inherent_methods( - ty: &Canonical, + self_ty: &Canonical, db: &impl HirDatabase, name: Option<&Name>, - mode: LookupMode, + receiver_ty: Option<&Canonical>, krate: CrateId, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { - for krate in ty.value.def_crates(db, krate)? { + for krate in self_ty.value.def_crates(db, krate)? { let impls = db.impls_in_crate(krate); - for impl_block in impls.lookup_impl_blocks(&ty.value) { + for impl_block in impls.lookup_impl_blocks(&self_ty.value) { for &item in db.impl_data(impl_block).items.iter() { - if !is_valid_candidate(db, name, mode, item) { + if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { continue; } - if let Some(result) = callback(&ty.value, item.into()) { + if let Some(result) = callback(&self_ty.value, item) { return Some(result); } } @@ -298,18 +365,29 @@ fn iterate_inherent_methods( fn is_valid_candidate( db: &impl HirDatabase, name: Option<&Name>, - mode: LookupMode, + receiver_ty: Option<&Canonical>, item: AssocItemId, + self_ty: &Canonical, ) -> bool { match item { AssocItemId::FunctionId(m) => { let data = db.function_data(m); - name.map_or(true, |name| &data.name == name) - && (data.has_self_param || mode == LookupMode::Path) + if let Some(name) = name { + if &data.name != name { + return false; + } + } + if let Some(receiver_ty) = receiver_ty { + if !data.has_self_param { + return false; + } + // TODO compare receiver ty + } + true } AssocItemId::ConstId(c) => { let data = db.const_data(c); - name.map_or(true, |name| data.name.as_ref() == Some(name)) && (mode == LookupMode::Path) + name.map_or(true, |name| data.name.as_ref() == Some(name)) && receiver_ty.is_none() } _ => false, } diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index a3cc5cf95..be8768c62 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -3433,7 +3433,6 @@ pub fn baz() -> usize { 31usize } assert_eq!("(i32, usize)", type_at_pos(&db, pos)); } -#[ignore] #[test] fn method_resolution_trait_before_autoref() { let t = type_at( @@ -3449,7 +3448,6 @@ fn test() { S.foo()<|>; } assert_eq!(t, "u128"); } -#[ignore] #[test] fn method_resolution_by_value_before_autoref() { let t = type_at( -- cgit v1.2.3 From 599dab59824b164b1c24e2e51adeae1ac1307964 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 1 Dec 2019 20:30:28 +0100 Subject: Extract unification code to unify module --- crates/ra_hir_ty/src/infer.rs | 255 +++----------------------------- crates/ra_hir_ty/src/infer/coerce.rs | 10 +- crates/ra_hir_ty/src/infer/expr.rs | 30 ++-- crates/ra_hir_ty/src/infer/pat.rs | 4 +- crates/ra_hir_ty/src/infer/path.rs | 4 +- crates/ra_hir_ty/src/infer/unify.rs | 272 ++++++++++++++++++++++++++++++++++- 6 files changed, 312 insertions(+), 263 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index fe259371f..81afbd2b4 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -18,7 +18,6 @@ use std::mem; use std::ops::Index; use std::sync::Arc; -use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; use rustc_hash::FxHashMap; use hir_def::{ @@ -33,12 +32,11 @@ use hir_def::{ use hir_expand::{diagnostics::DiagnosticSink, name}; use ra_arena::map::ArenaMap; use ra_prof::profile; -use test_utils::tested_by; use super::{ primitive::{FloatTy, IntTy}, traits::{Guidance, Obligation, ProjectionPredicate, Solution}, - ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, + ApplicationTy, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, }; use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; @@ -191,7 +189,7 @@ struct InferenceContext<'a, D: HirDatabase> { owner: DefWithBodyId, body: Arc, resolver: Resolver, - var_unification_table: InPlaceUnificationTable, + table: unify::InferenceTable, trait_env: Arc, obligations: Vec, result: InferenceResult, @@ -209,7 +207,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn new(db: &'a D, owner: DefWithBodyId, resolver: Resolver) -> Self { InferenceContext { result: InferenceResult::default(), - var_unification_table: InPlaceUnificationTable::new(), + table: unify::InferenceTable::new(), obligations: Vec::default(), return_ty: Ty::Unknown, // set in collect_fn_signature trait_env: TraitEnvironment::lower(db, &resolver), @@ -224,13 +222,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_all(mut self) -> InferenceResult { // FIXME resolve obligations as well (use Guidance if necessary) let mut result = mem::replace(&mut self.result, InferenceResult::default()); - let mut tv_stack = Vec::new(); for ty in result.type_of_expr.values_mut() { - let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown)); + let resolved = self.table.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); *ty = resolved; } for ty in result.type_of_pat.values_mut() { - let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown)); + let resolved = self.table.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); *ty = resolved; } result @@ -275,96 +272,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.normalize_associated_types_in(ty) } - fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool { - substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth)) - } - - fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { - self.unify_inner(ty1, ty2, 0) - } - - fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { - if depth > 1000 { - // prevent stackoverflows - panic!("infinite recursion in unification"); - } - if ty1 == ty2 { - return true; - } - // try to resolve type vars first - let ty1 = self.resolve_ty_shallow(ty1); - let ty2 = self.resolve_ty_shallow(ty2); - match (&*ty1, &*ty2) { - (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { - self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) - } - _ => self.unify_inner_trivial(&ty1, &ty2), - } - } - - fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool { - match (ty1, ty2) { - (Ty::Unknown, _) | (_, Ty::Unknown) => true, - - (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) - | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) - | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) - | ( - Ty::Infer(InferTy::MaybeNeverTypeVar(tv1)), - Ty::Infer(InferTy::MaybeNeverTypeVar(tv2)), - ) => { - // both type vars are unknown since we tried to resolve them - self.var_unification_table.union(*tv1, *tv2); - true - } - - // The order of MaybeNeverTypeVar matters here. - // Unifying MaybeNeverTypeVar and TypeVar will let the latter become MaybeNeverTypeVar. - // Unifying MaybeNeverTypeVar and other concrete type will let the former become it. - (Ty::Infer(InferTy::TypeVar(tv)), other) - | (other, Ty::Infer(InferTy::TypeVar(tv))) - | (Ty::Infer(InferTy::MaybeNeverTypeVar(tv)), other) - | (other, Ty::Infer(InferTy::MaybeNeverTypeVar(tv))) - | (Ty::Infer(InferTy::IntVar(tv)), other @ ty_app!(TypeCtor::Int(_))) - | (other @ ty_app!(TypeCtor::Int(_)), Ty::Infer(InferTy::IntVar(tv))) - | (Ty::Infer(InferTy::FloatVar(tv)), other @ ty_app!(TypeCtor::Float(_))) - | (other @ ty_app!(TypeCtor::Float(_)), Ty::Infer(InferTy::FloatVar(tv))) => { - // the type var is unknown since we tried to resolve it - self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone())); - true - } - - _ => false, - } - } - - fn new_type_var(&mut self) -> Ty { - Ty::Infer(InferTy::TypeVar(self.var_unification_table.new_key(TypeVarValue::Unknown))) - } - - fn new_integer_var(&mut self) -> Ty { - Ty::Infer(InferTy::IntVar(self.var_unification_table.new_key(TypeVarValue::Unknown))) - } - - fn new_float_var(&mut self) -> Ty { - Ty::Infer(InferTy::FloatVar(self.var_unification_table.new_key(TypeVarValue::Unknown))) - } - - fn new_maybe_never_type_var(&mut self) -> Ty { - Ty::Infer(InferTy::MaybeNeverTypeVar( - self.var_unification_table.new_key(TypeVarValue::Unknown), - )) - } - /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { match ty { - Ty::Unknown => self.new_type_var(), + Ty::Unknown => self.table.new_type_var(), Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => { - self.new_integer_var() + self.table.new_integer_var() } Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => { - self.new_float_var() + self.table.new_float_var() } _ => ty, } @@ -402,64 +318,22 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } + fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { + self.table.unify(ty1, ty2) + } + /// Resolves the type as far as currently possible, replacing type variables /// by their known types. All types returned by the infer_* functions should /// be resolved as far as possible, i.e. contain no type variables with /// known type. - fn resolve_ty_as_possible(&mut self, tv_stack: &mut Vec, ty: Ty) -> Ty { + fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { self.resolve_obligations_as_possible(); - ty.fold(&mut |ty| match ty { - Ty::Infer(tv) => { - let inner = tv.to_inner(); - if tv_stack.contains(&inner) { - tested_by!(type_var_cycles_resolve_as_possible); - // recursive type - return tv.fallback_value(); - } - if let Some(known_ty) = - self.var_unification_table.inlined_probe_value(inner).known() - { - // known_ty may contain other variables that are known by now - tv_stack.push(inner); - let result = self.resolve_ty_as_possible(tv_stack, known_ty.clone()); - tv_stack.pop(); - result - } else { - ty - } - } - _ => ty, - }) + self.table.resolve_ty_as_possible(ty) } - /// If `ty` is a type variable with known type, returns that type; - /// otherwise, return ty. fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { - let mut ty = Cow::Borrowed(ty); - // The type variable could resolve to a int/float variable. Hence try - // resolving up to three times; each type of variable shouldn't occur - // more than once - for i in 0..3 { - if i > 0 { - tested_by!(type_var_resolves_to_int_var); - } - match &*ty { - Ty::Infer(tv) => { - let inner = tv.to_inner(); - match self.var_unification_table.inlined_probe_value(inner).known() { - Some(known_ty) => { - // The known_ty can't be a type var itself - ty = Cow::Owned(known_ty.clone()); - } - _ => return ty, - } - } - _ => return ty, - } - } - log::error!("Inference variable still not resolved: {:?}", ty); - ty + self.table.resolve_ty_shallow(ty) } /// Recurses through the given type, normalizing associated types mentioned @@ -469,7 +343,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { /// call). `make_ty` handles this already, but e.g. for field types we need /// to do it as well. fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { - let ty = self.resolve_ty_as_possible(&mut vec![], ty); + let ty = self.resolve_ty_as_possible(ty); ty.fold(&mut |ty| match ty { Ty::Projection(proj_ty) => self.normalize_projection_ty(proj_ty), _ => ty, @@ -477,40 +351,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { - let var = self.new_type_var(); + let var = self.table.new_type_var(); let predicate = ProjectionPredicate { projection_ty: proj_ty, ty: var.clone() }; let obligation = Obligation::Projection(predicate); self.obligations.push(obligation); var } - /// Resolves the type completely; type variables without known type are - /// replaced by Ty::Unknown. - fn resolve_ty_completely(&mut self, tv_stack: &mut Vec, ty: Ty) -> Ty { - ty.fold(&mut |ty| match ty { - Ty::Infer(tv) => { - let inner = tv.to_inner(); - if tv_stack.contains(&inner) { - tested_by!(type_var_cycles_resolve_completely); - // recursive type - return tv.fallback_value(); - } - if let Some(known_ty) = - self.var_unification_table.inlined_probe_value(inner).known() - { - // known_ty may contain other variables that are known by now - tv_stack.push(inner); - let result = self.resolve_ty_completely(tv_stack, known_ty.clone()); - tv_stack.pop(); - result - } else { - tv.fallback_value() - } - } - _ => ty, - }) - } - fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option) { let path = match path { Some(path) => path, @@ -615,78 +462,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } -/// The ID of a type variable. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct TypeVarId(pub(super) u32); - -impl UnifyKey for TypeVarId { - type Value = TypeVarValue; - - fn index(&self) -> u32 { - self.0 - } - - fn from_index(i: u32) -> Self { - TypeVarId(i) - } - - fn tag() -> &'static str { - "TypeVarId" - } -} - -/// The value of a type variable: either we already know the type, or we don't -/// know it yet. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum TypeVarValue { - Known(Ty), - Unknown, -} - -impl TypeVarValue { - fn known(&self) -> Option<&Ty> { - match self { - TypeVarValue::Known(ty) => Some(ty), - TypeVarValue::Unknown => None, - } - } -} - -impl UnifyValue for TypeVarValue { - type Error = NoError; - - fn unify_values(value1: &Self, value2: &Self) -> Result { - match (value1, value2) { - // We should never equate two type variables, both of which have - // known types. Instead, we recursively equate those types. - (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!( - "equating two type variables, both of which have known types: {:?} and {:?}", - t1, t2 - ), - - // If one side is known, prefer that one. - (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()), - (TypeVarValue::Unknown, TypeVarValue::Known(..)) => Ok(value2.clone()), - - (TypeVarValue::Unknown, TypeVarValue::Unknown) => Ok(TypeVarValue::Unknown), - } - } -} - /// The kinds of placeholders we need during type inference. There's separate /// values for general types, and for integer and float variables. The latter /// two are used for inference of literal values (e.g. `100` could be one of /// several integer types). #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum InferTy { - TypeVar(TypeVarId), - IntVar(TypeVarId), - FloatVar(TypeVarId), - MaybeNeverTypeVar(TypeVarId), + TypeVar(unify::TypeVarId), + IntVar(unify::TypeVarId), + FloatVar(unify::TypeVarId), + MaybeNeverTypeVar(unify::TypeVarId), } impl InferTy { - fn to_inner(self) -> TypeVarId { + fn to_inner(self) -> unify::TypeVarId { match self { InferTy::TypeVar(ty) | InferTy::IntVar(ty) diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 064993d34..9bfc701cd 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs @@ -10,7 +10,7 @@ use test_utils::tested_by; use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk}; -use super::{InEnvironment, InferTy, InferenceContext, TypeVarValue}; +use super::{InEnvironment, InferTy, InferenceContext, unify::TypeVarValue}; impl<'a, D: HirDatabase> InferenceContext<'a, D> { /// Unify two types, but may coerce the first one to the second one @@ -85,8 +85,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { match (&from_ty, to_ty) { // Never type will make type variable to fallback to Never Type instead of Unknown. (ty_app!(TypeCtor::Never), Ty::Infer(InferTy::TypeVar(tv))) => { - let var = self.new_maybe_never_type_var(); - self.var_unification_table.union_value(*tv, TypeVarValue::Known(var)); + let var = self.table.new_maybe_never_type_var(); + self.table.var_unification_table.union_value(*tv, TypeVarValue::Known(var)); return true; } (ty_app!(TypeCtor::Never), _) => return true, @@ -94,7 +94,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // Trivial cases, this should go after `never` check to // avoid infer result type to be never _ => { - if self.unify_inner_trivial(&from_ty, &to_ty) { + if self.table.unify_inner_trivial(&from_ty, &to_ty) { return true; } } @@ -330,7 +330,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // Stop when constructor matches. (ty_app!(from_ctor, st1), ty_app!(to_ctor, st2)) if from_ctor == to_ctor => { // It will not recurse to `coerce`. - return self.unify_substs(st1, st2, 0); + return self.table.unify_substs(st1, st2, 0); } _ => {} } diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 4014f4732..1e78f6efd 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -32,7 +32,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, ); } - let ty = self.resolve_ty_as_possible(&mut vec![], ty); + let ty = self.resolve_ty_as_possible(ty); ty } @@ -53,7 +53,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { expected.ty.clone() }; - self.resolve_ty_as_possible(&mut vec![], ty) + self.resolve_ty_as_possible(ty) } fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { @@ -94,7 +94,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let pat_ty = match self.resolve_into_iter_item() { Some(into_iter_item_alias) => { - let pat_ty = self.new_type_var(); + let pat_ty = self.table.new_type_var(); let projection = ProjectionPredicate { ty: pat_ty.clone(), projection_ty: ProjectionTy { @@ -103,7 +103,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }, }; self.obligations.push(Obligation::Projection(projection)); - self.resolve_ty_as_possible(&mut vec![], pat_ty) + self.resolve_ty_as_possible(pat_ty) } None => Ty::Unknown, }; @@ -128,7 +128,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } // add return type - let ret_ty = self.new_type_var(); + let ret_ty = self.table.new_type_var(); sig_tys.push(ret_ty.clone()); let sig_ty = Ty::apply( TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, @@ -167,7 +167,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Expr::Match { expr, arms } => { let input_ty = self.infer_expr(*expr, &Expectation::none()); - let mut result_ty = self.new_maybe_never_type_var(); + let mut result_ty = self.table.new_maybe_never_type_var(); for arm in arms { for &pat in &arm.pats { @@ -283,7 +283,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let inner_ty = self.infer_expr(*expr, &Expectation::none()); let ty = match self.resolve_future_future_output() { Some(future_future_output_alias) => { - let ty = self.new_type_var(); + let ty = self.table.new_type_var(); let projection = ProjectionPredicate { ty: ty.clone(), projection_ty: ProjectionTy { @@ -292,7 +292,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }, }; self.obligations.push(Obligation::Projection(projection)); - self.resolve_ty_as_possible(&mut vec![], ty) + self.resolve_ty_as_possible(ty) } None => Ty::Unknown, }; @@ -302,7 +302,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let inner_ty = self.infer_expr(*expr, &Expectation::none()); let ty = match self.resolve_ops_try_ok() { Some(ops_try_ok_alias) => { - let ty = self.new_type_var(); + let ty = self.table.new_type_var(); let projection = ProjectionPredicate { ty: ty.clone(), projection_ty: ProjectionTy { @@ -311,7 +311,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }, }; self.obligations.push(Obligation::Projection(projection)); - self.resolve_ty_as_possible(&mut vec![], ty) + self.resolve_ty_as_possible(ty) } None => Ty::Unknown, }; @@ -465,10 +465,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ty_app!(TypeCtor::Tuple { .. }, st) => st .iter() .cloned() - .chain(repeat_with(|| self.new_type_var())) + .chain(repeat_with(|| self.table.new_type_var())) .take(exprs.len()) .collect::>(), - _ => (0..exprs.len()).map(|_| self.new_type_var()).collect(), + _ => (0..exprs.len()).map(|_| self.table.new_type_var()).collect(), }; for (expr, ty) in exprs.iter().zip(tys.iter_mut()) { @@ -482,7 +482,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => { st.as_single().clone() } - _ => self.new_type_var(), + _ => self.table.new_type_var(), }; match array { @@ -524,7 +524,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }; // use a new type variable if we got Ty::Unknown here let ty = self.insert_type_vars_shallow(ty); - let ty = self.resolve_ty_as_possible(&mut vec![], ty); + let ty = self.resolve_ty_as_possible(ty); self.write_expr_ty(tgt_expr, ty.clone()); ty } @@ -553,7 +553,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } - let ty = self.resolve_ty_as_possible(&mut vec![], ty); + let ty = self.resolve_ty_as_possible(ty); self.infer_pat(*pat, &ty, BindingMode::default()); } Statement::Expr(expr) => { diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs index 1ebb36239..a14662884 100644 --- a/crates/ra_hir_ty/src/infer/pat.rs +++ b/crates/ra_hir_ty/src/infer/pat.rs @@ -170,7 +170,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } BindingMode::Move => inner_ty.clone(), }; - let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); + let bound_ty = self.resolve_ty_as_possible(bound_ty); self.write_pat_ty(pat, bound_ty); return inner_ty; } @@ -179,7 +179,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // use a new type variable if we got Ty::Unknown here let ty = self.insert_type_vars_shallow(ty); self.unify(&ty, expected); - let ty = self.resolve_ty_as_possible(&mut vec![], ty); + let ty = self.resolve_ty_as_possible(ty); self.write_pat_ty(pat, ty.clone()); ty } diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index bbf146418..d0d7646a4 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -57,7 +57,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let typable: ValueTyDefId = match value { ValueNs::LocalBinding(pat) => { let ty = self.result.type_of_pat.get(pat)?.clone(); - let ty = self.resolve_ty_as_possible(&mut vec![], ty); + let ty = self.resolve_ty_as_possible(ty); return Some(ty); } ValueNs::FunctionId(it) => it.into(), @@ -211,7 +211,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // we're picking this method let trait_substs = Substs::build_for_def(self.db, trait_) .push(ty.clone()) - .fill(std::iter::repeat_with(|| self.new_type_var())) + .fill(std::iter::repeat_with(|| self.table.new_type_var())) .build(); let substs = Substs::build_for_def(self.db, item) .use_parent_substs(&trait_substs) diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index f3a875678..ff50138f5 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs @@ -1,9 +1,15 @@ //! Unification and canonicalization logic. +use std::borrow::Cow; + +use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; + +use test_utils::tested_by; + use super::{InferenceContext, Obligation}; use crate::{ db::HirDatabase, utils::make_mut_slice, Canonical, InEnvironment, InferTy, ProjectionPredicate, - ProjectionTy, Substs, TraitRef, Ty, TypeWalk, + ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }; impl<'a, D: HirDatabase> InferenceContext<'a, D> { @@ -24,7 +30,7 @@ where /// A stack of type variables that is used to detect recursive types (which /// are an error, but we need to protect against them to avoid stack /// overflows). - var_stack: Vec, + var_stack: Vec, } pub(super) struct Canonicalized { @@ -53,14 +59,14 @@ where return tv.fallback_value(); } if let Some(known_ty) = - self.ctx.var_unification_table.inlined_probe_value(inner).known() + self.ctx.table.var_unification_table.inlined_probe_value(inner).known() { self.var_stack.push(inner); let result = self.do_canonicalize_ty(known_ty.clone()); self.var_stack.pop(); result } else { - let root = self.ctx.var_unification_table.find(inner); + let root = self.ctx.table.var_unification_table.find(inner); let free_var = match tv { InferTy::TypeVar(_) => InferTy::TypeVar(root), InferTy::IntVar(_) => InferTy::IntVar(root), @@ -153,10 +159,264 @@ impl Canonicalized { solution: Canonical>, ) { // the solution may contain new variables, which we need to convert to new inference vars - let new_vars = Substs((0..solution.num_vars).map(|_| ctx.new_type_var()).collect()); + let new_vars = Substs((0..solution.num_vars).map(|_| ctx.table.new_type_var()).collect()); for (i, ty) in solution.value.into_iter().enumerate() { let var = self.free_vars[i]; - ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars)); + ctx.table.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars)); + } + } +} + +pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Substs { + let mut table = InferenceTable::new(); + let vars = Substs::builder(ty1.num_vars) + .fill(std::iter::repeat_with(|| table.new_type_var())).build(); + let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars); + table.unify(&ty_with_vars, ty2); + Substs::builder(ty1.num_vars).fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))).build() +} + +#[derive(Clone, Debug)] +pub(crate) struct InferenceTable { + pub(super) var_unification_table: InPlaceUnificationTable, +} + +impl InferenceTable { + pub fn new() -> Self { + InferenceTable { + var_unification_table: InPlaceUnificationTable::new(), + } + } + + pub fn new_type_var(&mut self) -> Ty { + Ty::Infer(InferTy::TypeVar(self.var_unification_table.new_key(TypeVarValue::Unknown))) + } + + pub fn new_integer_var(&mut self) -> Ty { + Ty::Infer(InferTy::IntVar(self.var_unification_table.new_key(TypeVarValue::Unknown))) + } + + pub fn new_float_var(&mut self) -> Ty { + Ty::Infer(InferTy::FloatVar(self.var_unification_table.new_key(TypeVarValue::Unknown))) + } + + pub fn new_maybe_never_type_var(&mut self) -> Ty { + Ty::Infer(InferTy::MaybeNeverTypeVar( + self.var_unification_table.new_key(TypeVarValue::Unknown), + )) + } + + pub fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { + self.resolve_ty_completely_inner(&mut Vec::new(), ty) + } + + pub fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { + self.resolve_ty_as_possible_inner(&mut Vec::new(), ty) + } + + pub fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { + self.unify_inner(ty1, ty2, 0) + } + + pub fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool { + substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth)) + } + + fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { + if depth > 1000 { + // prevent stackoverflows + panic!("infinite recursion in unification"); + } + if ty1 == ty2 { + return true; + } + // try to resolve type vars first + let ty1 = self.resolve_ty_shallow(ty1); + let ty2 = self.resolve_ty_shallow(ty2); + match (&*ty1, &*ty2) { + (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { + self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) + } + _ => self.unify_inner_trivial(&ty1, &ty2), + } + } + + pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool { + match (ty1, ty2) { + (Ty::Unknown, _) | (_, Ty::Unknown) => true, + + (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) + | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) + | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) + | ( + Ty::Infer(InferTy::MaybeNeverTypeVar(tv1)), + Ty::Infer(InferTy::MaybeNeverTypeVar(tv2)), + ) => { + // both type vars are unknown since we tried to resolve them + self.var_unification_table.union(*tv1, *tv2); + true + } + + // The order of MaybeNeverTypeVar matters here. + // Unifying MaybeNeverTypeVar and TypeVar will let the latter become MaybeNeverTypeVar. + // Unifying MaybeNeverTypeVar and other concrete type will let the former become it. + (Ty::Infer(InferTy::TypeVar(tv)), other) + | (other, Ty::Infer(InferTy::TypeVar(tv))) + | (Ty::Infer(InferTy::MaybeNeverTypeVar(tv)), other) + | (other, Ty::Infer(InferTy::MaybeNeverTypeVar(tv))) + | (Ty::Infer(InferTy::IntVar(tv)), other @ ty_app!(TypeCtor::Int(_))) + | (other @ ty_app!(TypeCtor::Int(_)), Ty::Infer(InferTy::IntVar(tv))) + | (Ty::Infer(InferTy::FloatVar(tv)), other @ ty_app!(TypeCtor::Float(_))) + | (other @ ty_app!(TypeCtor::Float(_)), Ty::Infer(InferTy::FloatVar(tv))) => { + // the type var is unknown since we tried to resolve it + self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone())); + true + } + + _ => false, + } + } + + /// If `ty` is a type variable with known type, returns that type; + /// otherwise, return ty. + pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { + let mut ty = Cow::Borrowed(ty); + // The type variable could resolve to a int/float variable. Hence try + // resolving up to three times; each type of variable shouldn't occur + // more than once + for i in 0..3 { + if i > 0 { + tested_by!(type_var_resolves_to_int_var); + } + match &*ty { + Ty::Infer(tv) => { + let inner = tv.to_inner(); + match self.var_unification_table.inlined_probe_value(inner).known() { + Some(known_ty) => { + // The known_ty can't be a type var itself + ty = Cow::Owned(known_ty.clone()); + } + _ => return ty, + } + } + _ => return ty, + } + } + log::error!("Inference variable still not resolved: {:?}", ty); + ty + } + + /// Resolves the type as far as currently possible, replacing type variables + /// by their known types. All types returned by the infer_* functions should + /// be resolved as far as possible, i.e. contain no type variables with + /// known type. + fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec, ty: Ty) -> Ty { + ty.fold(&mut |ty| match ty { + Ty::Infer(tv) => { + let inner = tv.to_inner(); + if tv_stack.contains(&inner) { + tested_by!(type_var_cycles_resolve_as_possible); + // recursive type + return tv.fallback_value(); + } + if let Some(known_ty) = + self.var_unification_table.inlined_probe_value(inner).known() + { + // known_ty may contain other variables that are known by now + tv_stack.push(inner); + let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone()); + tv_stack.pop(); + result + } else { + ty + } + } + _ => ty, + }) + } + + /// Resolves the type completely; type variables without known type are + /// replaced by Ty::Unknown. + fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec, ty: Ty) -> Ty { + ty.fold(&mut |ty| match ty { + Ty::Infer(tv) => { + let inner = tv.to_inner(); + if tv_stack.contains(&inner) { + tested_by!(type_var_cycles_resolve_completely); + // recursive type + return tv.fallback_value(); + } + if let Some(known_ty) = + self.var_unification_table.inlined_probe_value(inner).known() + { + // known_ty may contain other variables that are known by now + tv_stack.push(inner); + let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone()); + tv_stack.pop(); + result + } else { + tv.fallback_value() + } + } + _ => ty, + }) + } +} + +/// The ID of a type variable. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct TypeVarId(pub(super) u32); + +impl UnifyKey for TypeVarId { + type Value = TypeVarValue; + + fn index(&self) -> u32 { + self.0 + } + + fn from_index(i: u32) -> Self { + TypeVarId(i) + } + + fn tag() -> &'static str { + "TypeVarId" + } +} + +/// The value of a type variable: either we already know the type, or we don't +/// know it yet. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TypeVarValue { + Known(Ty), + Unknown, +} + +impl TypeVarValue { + fn known(&self) -> Option<&Ty> { + match self { + TypeVarValue::Known(ty) => Some(ty), + TypeVarValue::Unknown => None, + } + } +} + +impl UnifyValue for TypeVarValue { + type Error = NoError; + + fn unify_values(value1: &Self, value2: &Self) -> Result { + match (value1, value2) { + // We should never equate two type variables, both of which have + // known types. Instead, we recursively equate those types. + (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!( + "equating two type variables, both of which have known types: {:?} and {:?}", + t1, t2 + ), + + // If one side is known, prefer that one. + (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()), + (TypeVarValue::Unknown, TypeVarValue::Known(..)) => Ok(value2.clone()), + + (TypeVarValue::Unknown, TypeVarValue::Unknown) => Ok(TypeVarValue::Unknown), } } } -- cgit v1.2.3 From 456d52fdfa8525af2a54e76ee5300f0a40ef582a Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 1 Dec 2019 22:14:28 +0100 Subject: Check receiver type properly --- crates/ra_hir_ty/src/infer.rs | 6 ++- crates/ra_hir_ty/src/infer/coerce.rs | 2 +- crates/ra_hir_ty/src/infer/unify.rs | 20 +++++---- crates/ra_hir_ty/src/method_resolution.rs | 71 +++++++++++++++++++++++++++---- 4 files changed, 80 insertions(+), 19 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 81afbd2b4..0889a6bf9 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -36,11 +36,13 @@ use ra_prof::profile; use super::{ primitive::{FloatTy, IntTy}, traits::{Guidance, Obligation, ProjectionPredicate, Solution}, - ApplicationTy, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeCtor, - TypeWalk, Uncertain, + ApplicationTy, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, + Uncertain, }; use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; +pub use unify::unify; + macro_rules! ty_app { ($ctor:pat, $param:pat) => { crate::Ty::Apply(crate::ApplicationTy { ctor: $ctor, parameters: $param }) diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 9bfc701cd..9daa77cfa 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs @@ -10,7 +10,7 @@ use test_utils::tested_by; use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk}; -use super::{InEnvironment, InferTy, InferenceContext, unify::TypeVarValue}; +use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext}; impl<'a, D: HirDatabase> InferenceContext<'a, D> { /// Unify two types, but may coerce the first one to the second one diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index ff50138f5..8ed2a6090 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs @@ -167,13 +167,19 @@ impl Canonicalized { } } -pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Substs { +pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Option { let mut table = InferenceTable::new(); - let vars = Substs::builder(ty1.num_vars) - .fill(std::iter::repeat_with(|| table.new_type_var())).build(); + let vars = + Substs::builder(ty1.num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars); - table.unify(&ty_with_vars, ty2); - Substs::builder(ty1.num_vars).fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))).build() + if !table.unify(&ty_with_vars, ty2) { + return None; + } + Some( + Substs::builder(ty1.num_vars) + .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) + .build(), + ) } #[derive(Clone, Debug)] @@ -183,9 +189,7 @@ pub(crate) struct InferenceTable { impl InferenceTable { pub fn new() -> Self { - InferenceTable { - var_unification_table: InPlaceUnificationTable::new(), - } + InferenceTable { var_unification_table: InPlaceUnificationTable::new() } } pub fn new_type_var(&mut self) -> Ty { diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index fbb932a3e..97281cf15 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -7,19 +7,20 @@ use std::sync::Arc; use arrayvec::ArrayVec; use hir_def::{ lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, AstItemDef, - FunctionId, HasModule, ImplId, TraitId, + FunctionId, HasModule, ImplId, Lookup, TraitId, }; use hir_expand::name::Name; use ra_db::CrateId; use ra_prof::profile; use rustc_hash::FxHashMap; +use super::Substs; use crate::{ autoderef, db::HirDatabase, primitive::{FloatBitness, Uncertain}, utils::all_super_traits, - Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, + Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, }; /// This is used as a key for indexing impls. @@ -231,21 +232,42 @@ fn iterate_method_candidates_autoref( name: Option<&Name>, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { - if let Some(result) = iterate_method_candidates_by_receiver(&deref_chain[0], &deref_chain[1..], db, resolver, name, &mut callback) { + if let Some(result) = iterate_method_candidates_by_receiver( + &deref_chain[0], + &deref_chain[1..], + db, + resolver, + name, + &mut callback, + ) { return Some(result); } let refed = Canonical { num_vars: deref_chain[0].num_vars, value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), }; - if let Some(result) = iterate_method_candidates_by_receiver(&refed, deref_chain, db, resolver, name, &mut callback) { + if let Some(result) = iterate_method_candidates_by_receiver( + &refed, + deref_chain, + db, + resolver, + name, + &mut callback, + ) { return Some(result); } let ref_muted = Canonical { num_vars: deref_chain[0].num_vars, value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), }; - if let Some(result) = iterate_method_candidates_by_receiver(&ref_muted, deref_chain, db, resolver, name, &mut callback) { + if let Some(result) = iterate_method_candidates_by_receiver( + &ref_muted, + deref_chain, + db, + resolver, + name, + &mut callback, + ) { return Some(result); } None @@ -264,7 +286,14 @@ fn iterate_method_candidates_by_receiver( // be found in any of the derefs of receiver_ty, so we have to go through // that. for self_ty in std::iter::once(receiver_ty).chain(deref_chain) { - if let Some(result) = iterate_method_candidates_inner(self_ty, db, resolver, name, Some(receiver_ty), &mut callback) { + if let Some(result) = iterate_method_candidates_inner( + self_ty, + db, + resolver, + name, + Some(receiver_ty), + &mut callback, + ) { return Some(result); } } @@ -280,7 +309,9 @@ fn iterate_method_candidates_inner( mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { let krate = resolver.krate()?; - if let Some(result) = iterate_inherent_methods(self_ty, db, name, receiver_ty, krate, &mut callback) { + if let Some(result) = + iterate_inherent_methods(self_ty, db, name, receiver_ty, krate, &mut callback) + { return Some(result); } if let Some(result) = @@ -381,7 +412,31 @@ fn is_valid_candidate( if !data.has_self_param { return false; } - // TODO compare receiver ty + let substs = match m.lookup(db).container { + hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, item) + .push(self_ty.value.clone()) + .fill_with_unknown() + .build(), + hir_def::ContainerId::ImplId(impl_id) => { + let vars = + Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); + let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); + let self_ty_with_vars = + Canonical { num_vars: vars.len(), value: &self_ty_with_vars }; + if let Some(substs) = super::infer::unify(self_ty_with_vars, &self_ty.value) + { + substs + } else { + return false; + } + } + hir_def::ContainerId::ModuleId(_) => unreachable!(), + }; + let sig = db.callable_item_signature(m.into()); + let receiver = sig.params()[0].clone().subst(&substs); + if receiver != receiver_ty.value { + return false; + } } true } -- cgit v1.2.3 From cfa50df33e1ebfa89f7fbdece7454699f858de92 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 2 Dec 2019 18:12:49 +0100 Subject: Refactor a bit --- crates/ra_hir_ty/src/infer/path.rs | 38 +----------- crates/ra_hir_ty/src/method_resolution.rs | 98 ++++++++++++++++++------------- crates/ra_hir_ty/src/tests.rs | 15 +++++ 3 files changed, 74 insertions(+), 77 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index d0d7646a4..b0024c6e1 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -206,7 +206,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { AssocItemId::TypeAliasId(_) => unreachable!(), }; let substs = match container { - ContainerId::ImplId(_) => self.find_self_types(&def, ty.clone()), + ContainerId::ImplId(impl_id) => { + method_resolution::inherent_impl_substs(self.db, impl_id, &ty) + } ContainerId::TraitId(trait_) => { // we're picking this method let trait_substs = Substs::build_for_def(self.db, trait_) @@ -231,38 +233,4 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }, ) } - - fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option { - if let ValueNs::FunctionId(func) = *def { - // We only do the infer if parent has generic params - let gen = self.db.generic_params(func.into()); - if gen.count_parent_params() == 0 { - return None; - } - - let impl_id = match func.lookup(self.db).container { - ContainerId::ImplId(it) => it, - _ => return None, - }; - let self_ty = self.db.impl_self_ty(impl_id).clone(); - let self_ty_substs = self_ty.substs()?; - let actual_substs = actual_def_ty.substs()?; - - let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()]; - - // The following code *link up* the function actual parma type - // and impl_block type param index - self_ty_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| { - if let Ty::Param { idx, .. } = param { - if let Some(s) = new_substs.get_mut(*idx as usize) { - *s = pty.clone(); - } - } - }); - - Some(Substs(new_substs.into())) - } else { - None - } - } } diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 97281cf15..21efb196a 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -191,13 +191,13 @@ pub fn iterate_method_candidates( let ty = InEnvironment { value: ty.clone(), environment }; let krate = resolver.krate()?; - // We have to be careful about the order of operations here. - // Consider the case where we're resolving `x.clone()` where `x: - // &Vec<_>`. This resolves to the clone method with self type - // `Vec<_>`, *not* `&_`. I.e. we need to consider methods where the - // receiver type exactly matches before cases where we have to do - // autoref. But in the autoderef steps, the `&_` self type comes up - // *before* the `Vec<_>` self type. + // We have to be careful about the order we're looking at candidates + // in here. Consider the case where we're resolving `x.clone()` + // where `x: &Vec<_>`. This resolves to the clone method with self + // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where + // the receiver type exactly matches before cases where we have to + // do autoref. But in the autoderef steps, the `&_` self type comes + // up *before* the `Vec<_>` self type. // // On the other hand, we don't want to just pick any by-value method // before any by-autoref method; it's just that we need to consider @@ -206,7 +206,7 @@ pub fn iterate_method_candidates( let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty.clone()).collect(); for i in 0..deref_chain.len() { - if let Some(result) = iterate_method_candidates_autoref( + if let Some(result) = iterate_method_candidates_with_autoref( &deref_chain[i..], db, resolver, @@ -220,12 +220,12 @@ pub fn iterate_method_candidates( } LookupMode::Path => { // No autoderef for path lookups - iterate_method_candidates_inner(&ty, db, resolver, name, None, &mut callback) + iterate_method_candidates_for_self_ty(&ty, db, resolver, name, &mut callback) } } } -fn iterate_method_candidates_autoref( +fn iterate_method_candidates_with_autoref( deref_chain: &[Canonical], db: &impl HirDatabase, resolver: &Resolver, @@ -275,18 +275,25 @@ fn iterate_method_candidates_autoref( fn iterate_method_candidates_by_receiver( receiver_ty: &Canonical, - deref_chain: &[Canonical], + rest_of_deref_chain: &[Canonical], db: &impl HirDatabase, resolver: &Resolver, name: Option<&Name>, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { - // TODO: do we need to do the whole loop for inherents before traits? // We're looking for methods with *receiver* type receiver_ty. These could // be found in any of the derefs of receiver_ty, so we have to go through // that. - for self_ty in std::iter::once(receiver_ty).chain(deref_chain) { - if let Some(result) = iterate_method_candidates_inner( + let krate = resolver.krate()?; + for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { + if let Some(result) = + iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback) + { + return Some(result); + } + } + for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { + if let Some(result) = iterate_trait_method_candidates( self_ty, db, resolver, @@ -300,22 +307,19 @@ fn iterate_method_candidates_by_receiver( None } -fn iterate_method_candidates_inner( +fn iterate_method_candidates_for_self_ty( self_ty: &Canonical, db: &impl HirDatabase, resolver: &Resolver, name: Option<&Name>, - receiver_ty: Option<&Canonical>, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { let krate = resolver.krate()?; - if let Some(result) = - iterate_inherent_methods(self_ty, db, name, receiver_ty, krate, &mut callback) - { + if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) { return Some(result); } if let Some(result) = - iterate_trait_method_candidates(self_ty, db, resolver, name, receiver_ty, &mut callback) + iterate_trait_method_candidates(self_ty, db, resolver, name, None, &mut callback) { return Some(result); } @@ -412,29 +416,11 @@ fn is_valid_candidate( if !data.has_self_param { return false; } - let substs = match m.lookup(db).container { - hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, item) - .push(self_ty.value.clone()) - .fill_with_unknown() - .build(), - hir_def::ContainerId::ImplId(impl_id) => { - let vars = - Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); - let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); - let self_ty_with_vars = - Canonical { num_vars: vars.len(), value: &self_ty_with_vars }; - if let Some(substs) = super::infer::unify(self_ty_with_vars, &self_ty.value) - { - substs - } else { - return false; - } - } - hir_def::ContainerId::ModuleId(_) => unreachable!(), + let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) { + Some(ty) => ty, + None => return false, }; - let sig = db.callable_item_signature(m.into()); - let receiver = sig.params()[0].clone().subst(&substs); - if receiver != receiver_ty.value { + if transformed_receiver_ty != receiver_ty.value { return false; } } @@ -448,6 +434,34 @@ fn is_valid_candidate( } } +pub(crate) fn inherent_impl_substs( + db: &impl HirDatabase, + impl_id: ImplId, + self_ty: &Ty, +) -> Option { + let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); + let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); + let self_ty_with_vars = Canonical { num_vars: vars.len(), value: &self_ty_with_vars }; + super::infer::unify(self_ty_with_vars, self_ty) +} + +fn transform_receiver_ty( + db: &impl HirDatabase, + function_id: FunctionId, + self_ty: &Canonical, +) -> Option { + let substs = match function_id.lookup(db).container { + hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, function_id) + .push(self_ty.value.clone()) + .fill_with_unknown() + .build(), + hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty.value)?, + hir_def::ContainerId::ModuleId(_) => unreachable!(), + }; + let sig = db.callable_item_signature(function_id.into()); + Some(sig.params()[0].clone().subst(&substs)) +} + pub fn implements_trait( ty: &Canonical, db: &impl HirDatabase, diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index be8768c62..d28e835c7 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -3493,6 +3493,21 @@ fn test() { S.foo()<|>; } assert_eq!(t, "i8"); } +#[test] +fn method_resolution_impl_ref_before_trait() { + let t = type_at( + r#" +//- /main.rs +trait Trait { fn foo(self) -> u128; } +struct S; +impl S { fn foo(&self) -> i8 { 0 } } +impl Trait for &S { fn foo(self) -> u128 { 0 } } +fn test() { S.foo()<|>; } +"#, + ); + assert_eq!(t, "i8"); +} + #[test] fn method_resolution_trait_autoderef() { let t = type_at( -- cgit v1.2.3 From a5a07bde049c59059bc4a68b16a49a174d22cf65 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 2 Dec 2019 19:27:31 +0100 Subject: Add tests for checking the impl self type --- crates/ra_hir_ty/src/tests.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index d28e835c7..d5b8d10e2 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -3433,6 +3433,20 @@ pub fn baz() -> usize { 31usize } assert_eq!("(i32, usize)", type_at_pos(&db, pos)); } +#[test] +fn method_resolution_unify_impl_self_type() { + let t = type_at( + r#" +//- /main.rs +struct S; +impl S { fn foo(&self) -> u8 {} } +impl S { fn foo(&self) -> i8 {} } +fn test() { (S::.foo(), S::.foo())<|>; } +"#, + ); + assert_eq!(t, "(u8, i8)"); +} + #[test] fn method_resolution_trait_before_autoref() { let t = type_at( -- cgit v1.2.3 From 176207f1e87bb1f2c70529cdbc66ae8c96584b03 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 3 Dec 2019 12:16:39 +0100 Subject: Extract built-in trait implementations to separate module This untangles the builtin logic from the Chalk translation. --- crates/ra_hir_ty/src/traits.rs | 1 + crates/ra_hir_ty/src/traits/builtin.rs | 161 +++++++++++++++++++++++++++++ crates/ra_hir_ty/src/traits/chalk.rs | 184 ++++++++++----------------------- 3 files changed, 219 insertions(+), 127 deletions(-) create mode 100644 crates/ra_hir_ty/src/traits/builtin.rs (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 76189a60b..d49f8fb4b 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs @@ -15,6 +15,7 @@ use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, use self::chalk::{from_chalk, ToChalk}; pub(crate) mod chalk; +mod builtin; #[derive(Debug, Clone)] pub struct TraitSolver { diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs new file mode 100644 index 000000000..598fd81e3 --- /dev/null +++ b/crates/ra_hir_ty/src/traits/builtin.rs @@ -0,0 +1,161 @@ +//! This module provides the built-in trait implementations, e.g. to make +//! closures implement `Fn`. +use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId}; +use hir_expand::name; +use ra_db::CrateId; + +use super::{AssocTyValue, Impl}; +use crate::{db::HirDatabase, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; + +pub(super) struct BuiltinImplData { + pub num_vars: usize, + pub trait_ref: TraitRef, + pub where_clauses: Vec, + pub assoc_ty_values: Vec, +} + +pub(super) struct BuiltinImplAssocTyValueData { + pub impl_: Impl, + pub assoc_ty_id: TypeAliasId, + pub num_vars: usize, + pub value: Ty, +} + +pub(super) fn get_builtin_impls( + db: &impl HirDatabase, + krate: CrateId, + ty: &Ty, + trait_: TraitId, + mut callback: impl FnMut(Impl), +) { + if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { + for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() + { + if let Some(actual_trait) = get_fn_trait(db, krate, fn_trait) { + if trait_ == actual_trait { + let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait }; + callback(Impl::ClosureFnTraitImpl(impl_)); + } + } + } + } +} + +pub(super) fn impl_datum( + db: &impl HirDatabase, + krate: CrateId, + impl_: Impl, +) -> Option { + match impl_ { + Impl::ImplBlock(_) => unreachable!(), + Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), + } +} + +pub(super) fn associated_ty_value( + db: &impl HirDatabase, + krate: CrateId, + data: AssocTyValue, +) -> BuiltinImplAssocTyValueData { + match data { + AssocTyValue::TypeAlias(_) => unreachable!(), + AssocTyValue::ClosureFnTraitImplOutput(data) => { + closure_fn_trait_output_assoc_ty_value(db, krate, data) + } + } +} + +fn closure_fn_trait_impl_datum( + db: &impl HirDatabase, + krate: CrateId, + data: super::ClosureFnTraitImplData, +) -> Option { + // for some closure |X, Y| -> Z: + // impl Fn<(T, U)> for closure V> { Output = V } + + let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait + + // validate FnOnce trait, since we need it in the assoc ty value definition + // and don't want to return a valid value only to find out later that FnOnce + // is broken + let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; + let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?; + + let num_args: u16 = match &db.body(data.def.into())[data.expr] { + Expr::Lambda { args, .. } => args.len() as u16, + _ => { + log::warn!("closure for closure type {:?} not found", data); + 0 + } + }; + + let arg_ty = Ty::apply( + TypeCtor::Tuple { cardinality: num_args }, + Substs::builder(num_args as usize).fill_with_bound_vars(0).build(), + ); + let sig_ty = Ty::apply( + TypeCtor::FnPtr { num_args }, + Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(), + ); + + let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty); + + let trait_ref = TraitRef { + trait_: trait_.into(), + substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(), + }; + + let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()); + + Some(BuiltinImplData { + num_vars: num_args as usize + 1, + trait_ref, + where_clauses: Vec::new(), + assoc_ty_values: vec![output_ty_id], + }) +} + +fn closure_fn_trait_output_assoc_ty_value( + db: &impl HirDatabase, + krate: CrateId, + data: super::ClosureFnTraitImplData, +) -> BuiltinImplAssocTyValueData { + let impl_ = Impl::ClosureFnTraitImpl(data.clone()); + + let num_args: u16 = match &db.body(data.def.into())[data.expr] { + Expr::Lambda { args, .. } => args.len() as u16, + _ => { + log::warn!("closure for closure type {:?} not found", data); + 0 + } + }; + + let output_ty = Ty::Bound(num_args.into()); + + let fn_once_trait = + get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist"); + + let output_ty_id = db + .trait_data(fn_once_trait) + .associated_type_by_name(&name::OUTPUT_TYPE) + .expect("assoc ty value should not exist"); + + BuiltinImplAssocTyValueData { + impl_, + assoc_ty_id: output_ty_id, + num_vars: num_args as usize + 1, + value: output_ty, + } +} + +fn get_fn_trait( + db: &impl HirDatabase, + krate: CrateId, + fn_trait: super::FnTrait, +) -> Option { + let target = db.lang_item(krate, fn_trait.lang_item_name().into())?; + match target { + LangItemTarget::TraitId(t) => Some(t), + _ => None, + } +} diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 104346ada..e3f02fa15 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -8,17 +8,16 @@ use chalk_ir::{ TypeName, UniverseIndex, }; use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; -use ra_db::CrateId; use hir_def::{ - expr::Expr, lang_item::LangItemTarget, AssocItemId, AstItemDef, ContainerId, GenericDefId, - ImplId, Lookup, TraitId, TypeAliasId, + AssocItemId, AstItemDef, ContainerId, GenericDefId, ImplId, Lookup, TraitId, TypeAliasId, +}; +use ra_db::{ + salsa::{InternId, InternKey}, + CrateId, }; -use hir_expand::name; - -use ra_db::salsa::{InternId, InternKey}; -use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; +use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; use crate::{ db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, @@ -395,6 +394,51 @@ where } } +impl ToChalk for builtin::BuiltinImplData { + type Chalk = chalk_rust_ir::ImplDatum; + + fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::ImplDatum { + let impl_type = chalk_rust_ir::ImplType::External; + let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect(); + + let impl_datum_bound = + chalk_rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses }; + let associated_ty_value_ids = + self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect(); + chalk_rust_ir::ImplDatum { + binders: make_binders(impl_datum_bound, self.num_vars), + impl_type, + polarity: chalk_rust_ir::Polarity::Positive, + associated_ty_value_ids, + } + } + + fn from_chalk(_db: &impl HirDatabase, _data: chalk_rust_ir::ImplDatum) -> Self { + unimplemented!() + } +} + +impl ToChalk for builtin::BuiltinImplAssocTyValueData { + type Chalk = chalk_rust_ir::AssociatedTyValue; + + fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::AssociatedTyValue { + let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: self.value.to_chalk(db) }; + + chalk_rust_ir::AssociatedTyValue { + associated_ty_id: self.assoc_ty_id.to_chalk(db), + impl_id: self.impl_.to_chalk(db), + value: make_binders(value_bound, self.num_vars), + } + } + + fn from_chalk( + _db: &impl HirDatabase, + _data: chalk_rust_ir::AssociatedTyValue, + ) -> builtin::BuiltinImplAssocTyValueData { + unimplemented!() + } +} + fn make_binders(value: T, num_vars: usize) -> chalk_ir::Binders { chalk_ir::Binders { value, @@ -456,18 +500,10 @@ where .collect(); let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); - if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { - for &fn_trait in - [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() - { - if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) { - if trait_ == actual_trait { - let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait }; - result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db)); - } - } - } - } + + builtin::get_builtin_impls(self.db, self.krate, &ty, trait_, |i| { + result.push(i.to_chalk(self.db)) + }); debug!("impls_for_trait returned {} impls", result.len()); result @@ -619,7 +655,7 @@ pub(crate) fn impl_datum_query( let impl_: Impl = from_chalk(db, impl_id); match impl_ { Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block), - Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), + _ => builtin::impl_datum(db, krate, impl_).map(|d| Arc::new(d.to_chalk(db))), } .unwrap_or_else(invalid_impl_datum) } @@ -700,63 +736,6 @@ fn invalid_impl_datum() -> Arc> { Arc::new(impl_datum) } -fn closure_fn_trait_impl_datum( - db: &impl HirDatabase, - krate: CrateId, - data: super::ClosureFnTraitImplData, -) -> Option>> { - // for some closure |X, Y| -> Z: - // impl Fn<(T, U)> for closure V> { Output = V } - - let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait - - // validate FnOnce trait, since we need it in the assoc ty value definition - // and don't want to return a valid value only to find out later that FnOnce - // is broken - let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; - let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?; - - let num_args: u16 = match &db.body(data.def.into())[data.expr] { - Expr::Lambda { args, .. } => args.len() as u16, - _ => { - log::warn!("closure for closure type {:?} not found", data); - 0 - } - }; - - let arg_ty = Ty::apply( - TypeCtor::Tuple { cardinality: num_args }, - Substs::builder(num_args as usize).fill_with_bound_vars(0).build(), - ); - let sig_ty = Ty::apply( - TypeCtor::FnPtr { num_args }, - Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(), - ); - - let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty); - - let trait_ref = TraitRef { - trait_: trait_.into(), - substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(), - }; - - let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()).to_chalk(db); - - let impl_type = chalk_rust_ir::ImplType::External; - - let impl_datum_bound = chalk_rust_ir::ImplDatumBound { - trait_ref: trait_ref.to_chalk(db), - where_clauses: Vec::new(), - }; - let impl_datum = ImplDatum { - binders: make_binders(impl_datum_bound, num_args as usize + 1), - impl_type, - polarity: chalk_rust_ir::Polarity::Positive, - associated_ty_value_ids: vec![output_ty_id], - }; - Some(Arc::new(impl_datum)) -} - pub(crate) fn associated_ty_value_query( db: &impl HirDatabase, krate: CrateId, @@ -767,9 +746,7 @@ pub(crate) fn associated_ty_value_query( AssocTyValue::TypeAlias(type_alias) => { type_alias_associated_ty_value(db, krate, type_alias) } - AssocTyValue::ClosureFnTraitImplOutput(data) => { - closure_fn_trait_output_assoc_ty_value(db, krate, data) - } + _ => Arc::new(builtin::associated_ty_value(db, krate, data).to_chalk(db)), } } @@ -802,53 +779,6 @@ fn type_alias_associated_ty_value( Arc::new(value) } -fn closure_fn_trait_output_assoc_ty_value( - db: &impl HirDatabase, - krate: CrateId, - data: super::ClosureFnTraitImplData, -) -> Arc> { - let impl_id = Impl::ClosureFnTraitImpl(data.clone()).to_chalk(db); - - let num_args: u16 = match &db.body(data.def.into())[data.expr] { - Expr::Lambda { args, .. } => args.len() as u16, - _ => { - log::warn!("closure for closure type {:?} not found", data); - 0 - } - }; - - let output_ty = Ty::Bound(num_args.into()); - - let fn_once_trait = - get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist"); - - let output_ty_id = db - .trait_data(fn_once_trait) - .associated_type_by_name(&name::OUTPUT_TYPE) - .expect("assoc ty value should not exist"); - - let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) }; - - let value = chalk_rust_ir::AssociatedTyValue { - associated_ty_id: output_ty_id.to_chalk(db), - impl_id, - value: make_binders(value_bound, num_args as usize + 1), - }; - Arc::new(value) -} - -fn get_fn_trait( - db: &impl HirDatabase, - krate: CrateId, - fn_trait: super::FnTrait, -) -> Option { - let target = db.lang_item(krate, fn_trait.lang_item_name().into())?; - match target { - LangItemTarget::TraitId(t) => Some(t), - _ => None, - } -} - fn id_from_chalk(chalk_id: chalk_ir::RawId) -> T { T::from_intern_id(InternId::from(chalk_id.index)) } -- cgit v1.2.3 From 18f25acb89304b2eb0a822b7b49b5e66a439ada7 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 3 Dec 2019 13:58:02 +0100 Subject: Make unify pub(crate) --- crates/ra_hir_ty/src/infer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 0889a6bf9..d16f1eb46 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -41,7 +41,7 @@ use super::{ }; use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; -pub use unify::unify; +pub(crate) use unify::unify; macro_rules! ty_app { ($ctor:pat, $param:pat) => { -- cgit v1.2.3 From e4add45951511f9afe348bf6066a724deb0d3ccf Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 3 Dec 2019 14:59:29 +0100 Subject: Fix #2467 The stand-alone `unify` requires that the type doesn't contain any type variables. So we can't share the code here for now (without more refactoring)... --- crates/ra_hir_ty/src/infer/path.rs | 13 ++++++++- crates/ra_hir_ty/src/infer/unify.rs | 4 +-- crates/ra_hir_ty/src/method_resolution.rs | 8 +++--- crates/ra_hir_ty/src/tests.rs | 47 +++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 7 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index b0024c6e1..37db005ea 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -1,5 +1,7 @@ //! Path expression resolution. +use std::iter; + use hir_def::{ path::{Path, PathKind, PathSegment}, resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, @@ -207,7 +209,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }; let substs = match container { ContainerId::ImplId(impl_id) => { - method_resolution::inherent_impl_substs(self.db, impl_id, &ty) + let impl_substs = Substs::build_for_def(self.db, impl_id) + .fill(iter::repeat_with(|| self.table.new_type_var())) + .build(); + let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs); + let substs = Substs::build_for_def(self.db, item) + .use_parent_substs(&impl_substs) + .fill_with_params() + .build(); + self.unify(&impl_self_ty, &ty); + Some(substs) } ContainerId::TraitId(trait_) => { // we're picking this method diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index 8ed2a6090..fe05642ae 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs @@ -167,12 +167,12 @@ impl Canonicalized { } } -pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Option { +pub fn unify(ty1: &Canonical, ty2: &Canonical) -> Option { let mut table = InferenceTable::new(); let vars = Substs::builder(ty1.num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars); - if !table.unify(&ty_with_vars, ty2) { + if !table.unify(&ty_with_vars, &ty2.value) { return None; } Some( diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 21efb196a..7220d6e0a 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -437,12 +437,12 @@ fn is_valid_candidate( pub(crate) fn inherent_impl_substs( db: &impl HirDatabase, impl_id: ImplId, - self_ty: &Ty, + self_ty: &Canonical, ) -> Option { let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); - let self_ty_with_vars = Canonical { num_vars: vars.len(), value: &self_ty_with_vars }; - super::infer::unify(self_ty_with_vars, self_ty) + let self_ty_with_vars = Canonical { num_vars: vars.len(), value: self_ty_with_vars }; + super::infer::unify(&self_ty_with_vars, self_ty) } fn transform_receiver_ty( @@ -455,7 +455,7 @@ fn transform_receiver_ty( .push(self_ty.value.clone()) .fill_with_unknown() .build(), - hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty.value)?, + hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?, hir_def::ContainerId::ModuleId(_) => unreachable!(), }; let sig = db.callable_item_signature(function_id.into()); diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index d5b8d10e2..2ea9e261c 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -4820,6 +4820,53 @@ fn test() where T: Trait, U: Trait { assert_eq!(t, "{unknown}"); } +#[test] +fn bug_2467() { + assert_snapshot!( + infer(r#" +struct S(T); +impl S { + fn foo(self) -> T; +} +fn test() { + // needs to nest multiple times for variable indices to get high enough + let a = S::foo(S(1)); + let b = S::foo(S(a)); + let c = S::foo(S(b)); + let d: u32 = S::foo(S(c)); +} +"#), + @r###" + [43; 47) 'self': S + [67; 255) '{ ...c)); }': () + [153; 154) 'a': u32 + [157; 163) 'S::foo': fn foo(S) -> T + [157; 169) 'S::foo(S(1))': u32 + [164; 165) 'S': S(T) -> S + [164; 168) 'S(1)': S + [166; 167) '1': u32 + [179; 180) 'b': u32 + [183; 189) 'S::foo': fn foo(S) -> T + [183; 195) 'S::foo(S(a))': u32 + [190; 191) 'S': S(T) -> S + [190; 194) 'S(a)': S + [192; 193) 'a': u32 + [205; 206) 'c': u32 + [209; 215) 'S::foo': fn foo(S) -> T + [209; 221) 'S::foo(S(b))': u32 + [216; 217) 'S': S(T) -> S + [216; 220) 'S(b)': S + [218; 219) 'b': u32 + [231; 232) 'd': u32 + [240; 246) 'S::foo': fn foo(S) -> T + [240; 252) 'S::foo(S(c))': u32 + [247; 248) 'S': S(T) -> S + [247; 251) 'S(c)': S + [249; 250) 'c': u32 + "### + ); +} + fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { let file = db.parse(pos.file_id).ok().unwrap(); let expr = algo::find_node_at_offset::(file.syntax(), pos.offset).unwrap(); -- cgit v1.2.3 From 009437f5d9949d2276aa26040e03af0ab328acf3 Mon Sep 17 00:00:00 2001 From: ice1000 Date: Tue, 3 Dec 2019 11:07:56 -0500 Subject: Replace `ra_hir_expand::either` with crate --- crates/ra_hir_ty/src/expr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index 5c65f9370..d2bd64e5c 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs @@ -97,7 +97,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { let (_, source_map) = db.body_with_source_map(self.func.into()); if let Some(source_ptr) = source_map.expr_syntax(id) { - if let Some(expr) = source_ptr.value.a() { + if let Some(expr) = source_ptr.value.left() { let root = source_ptr.file_syntax(db); if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { if let Some(field_list) = record_lit.record_field_list() { @@ -142,7 +142,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { let (_, source_map) = db.body_with_source_map(self.func.into()); if let Some(source_ptr) = source_map.expr_syntax(id) { - if let Some(expr) = source_ptr.value.a() { + if let Some(expr) = source_ptr.value.left() { self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); } } -- cgit v1.2.3 From 9747156f6c5c9b5cccc347a68042e6d9a6b0f704 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 3 Dec 2019 13:38:54 +0100 Subject: Split up ty tests a bit --- crates/ra_hir_ty/src/tests.rs | 4908 +---------------------- crates/ra_hir_ty/src/tests/macros.rs | 268 ++ crates/ra_hir_ty/src/tests/method_resolution.rs | 1005 +++++ crates/ra_hir_ty/src/tests/patterns.rs | 238 ++ crates/ra_hir_ty/src/tests/regression.rs | 333 ++ crates/ra_hir_ty/src/tests/simple.rs | 1608 ++++++++ crates/ra_hir_ty/src/tests/traits.rs | 1424 +++++++ 7 files changed, 4882 insertions(+), 4902 deletions(-) create mode 100644 crates/ra_hir_ty/src/tests/macros.rs create mode 100644 crates/ra_hir_ty/src/tests/method_resolution.rs create mode 100644 crates/ra_hir_ty/src/tests/patterns.rs create mode 100644 crates/ra_hir_ty/src/tests/regression.rs create mode 100644 crates/ra_hir_ty/src/tests/simple.rs create mode 100644 crates/ra_hir_ty/src/tests/traits.rs (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 2ea9e261c..c520bb375 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -1,5 +1,11 @@ mod never_type; mod coercion; +mod regression; +mod simple; +mod patterns; +mod traits; +mod method_resolution; +mod macros; use std::fmt::Write; use std::sync::Arc; @@ -15,7 +21,6 @@ use ra_syntax::{ algo, ast::{self, AstNode}, }; -use test_utils::covers; use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResult}; @@ -23,4850 +28,6 @@ use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResu // against snapshots of the expected results using insta. Use cargo-insta to // update the snapshots. -#[test] -fn cfg_impl_block() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs crate:main deps:foo cfg:test -use foo::S as T; -struct S; - -#[cfg(test)] -impl S { - fn foo1(&self) -> i32 { 0 } -} - -#[cfg(not(test))] -impl S { - fn foo2(&self) -> i32 { 0 } -} - -fn test() { - let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4()); - t<|>; -} - -//- /foo.rs crate:foo -struct S; - -#[cfg(not(test))] -impl S { - fn foo3(&self) -> i32 { 0 } -} - -#[cfg(test)] -impl S { - fn foo4(&self) -> i32 { 0 } -} -"#, - ); - assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos)); -} - -#[test] -fn infer_await() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs crate:main deps:std - -struct IntFuture; - -impl Future for IntFuture { - type Output = u64; -} - -fn test() { - let r = IntFuture; - let v = r.await; - v<|>; -} - -//- /std.rs crate:std -#[prelude_import] use future::*; -mod future { - trait Future { - type Output; - } -} - -"#, - ); - assert_eq!("u64", type_at_pos(&db, pos)); -} - -#[test] -fn infer_box() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs crate:main deps:std - -fn test() { - let x = box 1; - let t = (x, box x, box &1, box [1]); - t<|>; -} - -//- /std.rs crate:std -#[prelude_import] use prelude::*; -mod prelude {} - -mod boxed { - pub struct Box { - inner: *mut T, - } -} - -"#, - ); - assert_eq!("(Box, Box>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos)); -} - -#[test] -fn infer_adt_self() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs -enum Nat { Succ(Self), Demo(Nat), Zero } - -fn test() { - let foo: Nat = Nat::Zero; - if let Nat::Succ(x) = foo { - x<|> - } -} - -"#, - ); - assert_eq!("Nat", type_at_pos(&db, pos)); -} - -#[test] -fn infer_try() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs crate:main deps:std - -fn test() { - let r: Result = Result::Ok(1); - let v = r?; - v<|>; -} - -//- /std.rs crate:std - -#[prelude_import] use ops::*; -mod ops { - trait Try { - type Ok; - type Error; - } -} - -#[prelude_import] use result::*; -mod result { - enum Result { - Ok(O), - Err(E) - } - - impl crate::ops::Try for Result { - type Ok = O; - type Error = E; - } -} - -"#, - ); - assert_eq!("i32", type_at_pos(&db, pos)); -} - -#[test] -fn infer_for_loop() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs crate:main deps:std - -use std::collections::Vec; - -fn test() { - let v = Vec::new(); - v.push("foo"); - for x in v { - x<|>; - } -} - -//- /std.rs crate:std - -#[prelude_import] use iter::*; -mod iter { - trait IntoIterator { - type Item; - } -} - -mod collections { - struct Vec {} - impl Vec { - fn new() -> Self { Vec {} } - fn push(&mut self, t: T) { } - } - - impl crate::iter::IntoIterator for Vec { - type Item=T; - } -} -"#, - ); - assert_eq!("&str", type_at_pos(&db, pos)); -} - -#[test] -fn infer_ranges() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs crate:main deps:std -fn test() { - let a = ..; - let b = 1..; - let c = ..2u32; - let d = 1..2usize; - let e = ..=10; - let f = 'a'..='z'; - - let t = (a, b, c, d, e, f); - t<|>; -} - -//- /std.rs crate:std -#[prelude_import] use prelude::*; -mod prelude {} - -pub mod ops { - pub struct Range { - pub start: Idx, - pub end: Idx, - } - pub struct RangeFrom { - pub start: Idx, - } - struct RangeFull; - pub struct RangeInclusive { - start: Idx, - end: Idx, - is_empty: u8, - } - pub struct RangeTo { - pub end: Idx, - } - pub struct RangeToInclusive { - pub end: Idx, - } -} -"#, - ); - assert_eq!( - "(RangeFull, RangeFrom, RangeTo, Range, RangeToInclusive, RangeInclusive)", - type_at_pos(&db, pos), - ); -} - -#[test] -fn infer_while_let() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs -enum Option { Some(T), None } - -fn test() { - let foo: Option = None; - while let Option::Some(x) = foo { - <|>x - } -} - -"#, - ); - assert_eq!("f32", type_at_pos(&db, pos)); -} - -#[test] -fn infer_basics() { - assert_snapshot!( - infer(r#" -fn test(a: u32, b: isize, c: !, d: &str) { - a; - b; - c; - d; - 1usize; - 1isize; - "test"; - 1.0f32; -}"#), - @r###" - [9; 10) 'a': u32 - [17; 18) 'b': isize - [27; 28) 'c': ! - [33; 34) 'd': &str - [42; 121) '{ ...f32; }': ! - [48; 49) 'a': u32 - [55; 56) 'b': isize - [62; 63) 'c': ! - [69; 70) 'd': &str - [76; 82) '1usize': usize - [88; 94) '1isize': isize - [100; 106) '"test"': &str - [112; 118) '1.0f32': f32 - "### - ); -} - -#[test] -fn infer_let() { - assert_snapshot!( - infer(r#" -fn test() { - let a = 1isize; - let b: usize = 1; - let c = b; - let d: u32; - let e; - let f: i32 = e; -} -"#), - @r###" - [11; 118) '{ ...= e; }': () - [21; 22) 'a': isize - [25; 31) '1isize': isize - [41; 42) 'b': usize - [52; 53) '1': usize - [63; 64) 'c': usize - [67; 68) 'b': usize - [78; 79) 'd': u32 - [94; 95) 'e': i32 - [105; 106) 'f': i32 - [114; 115) 'e': i32 - "### - ); -} - -#[test] -fn infer_paths() { - assert_snapshot!( - infer(r#" -fn a() -> u32 { 1 } - -mod b { - fn c() -> u32 { 1 } -} - -fn test() { - a(); - b::c(); -} -"#), - @r###" - [15; 20) '{ 1 }': u32 - [17; 18) '1': u32 - [48; 53) '{ 1 }': u32 - [50; 51) '1': u32 - [67; 91) '{ ...c(); }': () - [73; 74) 'a': fn a() -> u32 - [73; 76) 'a()': u32 - [82; 86) 'b::c': fn c() -> u32 - [82; 88) 'b::c()': u32 - "### - ); -} - -#[test] -fn infer_path_type() { - assert_snapshot!( - infer(r#" -struct S; - -impl S { - fn foo() -> i32 { 1 } -} - -fn test() { - S::foo(); - ::foo(); -} -"#), - @r###" - [41; 46) '{ 1 }': i32 - [43; 44) '1': i32 - [60; 93) '{ ...o(); }': () - [66; 72) 'S::foo': fn foo() -> i32 - [66; 74) 'S::foo()': i32 - [80; 88) '::foo': fn foo() -> i32 - [80; 90) '::foo()': i32 - "### - ); -} - -#[test] -fn infer_slice_method() { - assert_snapshot!( - infer(r#" -#[lang = "slice"] -impl [T] { - fn foo(&self) -> T { - loop {} - } -} - -#[lang = "slice_alloc"] -impl [T] {} - -fn test() { - <[_]>::foo(b"foo"); -} -"#), - @r###" - [45; 49) 'self': &[T] - [56; 79) '{ ... }': T - [66; 73) 'loop {}': ! - [71; 73) '{}': () - [133; 160) '{ ...o"); }': () - [139; 149) '<[_]>::foo': fn foo(&[T]) -> T - [139; 157) '<[_]>:..."foo")': u8 - [150; 156) 'b"foo"': &[u8] - "### - ); -} - -#[test] -fn infer_struct() { - assert_snapshot!( - infer(r#" -struct A { - b: B, - c: C, -} -struct B; -struct C(usize); - -fn test() { - let c = C(1); - B; - let a: A = A { b: B, c: C(1) }; - a.b; - a.c; -} -"#), - @r###" - [72; 154) '{ ...a.c; }': () - [82; 83) 'c': C - [86; 87) 'C': C(usize) -> C - [86; 90) 'C(1)': C - [88; 89) '1': usize - [96; 97) 'B': B - [107; 108) 'a': A - [114; 133) 'A { b:...C(1) }': A - [121; 122) 'B': B - [127; 128) 'C': C(usize) -> C - [127; 131) 'C(1)': C - [129; 130) '1': usize - [139; 140) 'a': A - [139; 142) 'a.b': B - [148; 149) 'a': A - [148; 151) 'a.c': C - "### - ); -} - -#[test] -fn infer_enum() { - assert_snapshot!( - infer(r#" -enum E { - V1 { field: u32 }, - V2 -} -fn test() { - E::V1 { field: 1 }; - E::V2; -}"#), - @r###" - [48; 82) '{ E:...:V2; }': () - [52; 70) 'E::V1 ...d: 1 }': E - [67; 68) '1': u32 - [74; 79) 'E::V2': E - "### - ); -} - -#[test] -fn infer_refs() { - assert_snapshot!( - infer(r#" -fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { - a; - *a; - &a; - &mut a; - b; - *b; - &b; - c; - *c; - d; - *d; -} -"#), - @r###" - [9; 10) 'a': &u32 - [18; 19) 'b': &mut u32 - [31; 32) 'c': *const u32 - [46; 47) 'd': *mut u32 - [59; 150) '{ ... *d; }': () - [65; 66) 'a': &u32 - [72; 74) '*a': u32 - [73; 74) 'a': &u32 - [80; 82) '&a': &&u32 - [81; 82) 'a': &u32 - [88; 94) '&mut a': &mut &u32 - [93; 94) 'a': &u32 - [100; 101) 'b': &mut u32 - [107; 109) '*b': u32 - [108; 109) 'b': &mut u32 - [115; 117) '&b': &&mut u32 - [116; 117) 'b': &mut u32 - [123; 124) 'c': *const u32 - [130; 132) '*c': u32 - [131; 132) 'c': *const u32 - [138; 139) 'd': *mut u32 - [145; 147) '*d': u32 - [146; 147) 'd': *mut u32 - "### - ); -} - -#[test] -fn infer_literals() { - assert_snapshot!( - infer(r##" -fn test() { - 5i32; - 5f32; - 5f64; - "hello"; - b"bytes"; - 'c'; - b'b'; - 3.14; - 5000; - false; - true; - r#" - //! doc - // non-doc - mod foo {} - "#; - br#"yolo"#; -} -"##), - @r###" - [11; 221) '{ ...o"#; }': () - [17; 21) '5i32': i32 - [27; 31) '5f32': f32 - [37; 41) '5f64': f64 - [47; 54) '"hello"': &str - [60; 68) 'b"bytes"': &[u8] - [74; 77) ''c'': char - [83; 87) 'b'b'': u8 - [93; 97) '3.14': f64 - [103; 107) '5000': i32 - [113; 118) 'false': bool - [124; 128) 'true': bool - [134; 202) 'r#" ... "#': &str - [208; 218) 'br#"yolo"#': &[u8] - "### - ); -} - -#[test] -fn infer_unary_op() { - assert_snapshot!( - infer(r#" -enum SomeType {} - -fn test(x: SomeType) { - let b = false; - let c = !b; - let a = 100; - let d: i128 = -a; - let e = -100; - let f = !!!true; - let g = !42; - let h = !10u32; - let j = !a; - -3.14; - !3; - -x; - !x; - -"hello"; - !"hello"; -} -"#), - @r###" - [27; 28) 'x': SomeType - [40; 272) '{ ...lo"; }': () - [50; 51) 'b': bool - [54; 59) 'false': bool - [69; 70) 'c': bool - [73; 75) '!b': bool - [74; 75) 'b': bool - [85; 86) 'a': i128 - [89; 92) '100': i128 - [102; 103) 'd': i128 - [112; 114) '-a': i128 - [113; 114) 'a': i128 - [124; 125) 'e': i32 - [128; 132) '-100': i32 - [129; 132) '100': i32 - [142; 143) 'f': bool - [146; 153) '!!!true': bool - [147; 153) '!!true': bool - [148; 153) '!true': bool - [149; 153) 'true': bool - [163; 164) 'g': i32 - [167; 170) '!42': i32 - [168; 170) '42': i32 - [180; 181) 'h': u32 - [184; 190) '!10u32': u32 - [185; 190) '10u32': u32 - [200; 201) 'j': i128 - [204; 206) '!a': i128 - [205; 206) 'a': i128 - [212; 217) '-3.14': f64 - [213; 217) '3.14': f64 - [223; 225) '!3': i32 - [224; 225) '3': i32 - [231; 233) '-x': {unknown} - [232; 233) 'x': SomeType - [239; 241) '!x': {unknown} - [240; 241) 'x': SomeType - [247; 255) '-"hello"': {unknown} - [248; 255) '"hello"': &str - [261; 269) '!"hello"': {unknown} - [262; 269) '"hello"': &str - "### - ); -} - -#[test] -fn infer_backwards() { - assert_snapshot!( - infer(r#" -fn takes_u32(x: u32) {} - -struct S { i32_field: i32 } - -fn test() -> &mut &f64 { - let a = unknown_function(); - takes_u32(a); - let b = unknown_function(); - S { i32_field: b }; - let c = unknown_function(); - &mut &c -} -"#), - @r###" - [14; 15) 'x': u32 - [22; 24) '{}': () - [78; 231) '{ ...t &c }': &mut &f64 - [88; 89) 'a': u32 - [92; 108) 'unknow...nction': {unknown} - [92; 110) 'unknow...tion()': u32 - [116; 125) 'takes_u32': fn takes_u32(u32) -> () - [116; 128) 'takes_u32(a)': () - [126; 127) 'a': u32 - [138; 139) 'b': i32 - [142; 158) 'unknow...nction': {unknown} - [142; 160) 'unknow...tion()': i32 - [166; 184) 'S { i3...d: b }': S - [181; 182) 'b': i32 - [194; 195) 'c': f64 - [198; 214) 'unknow...nction': {unknown} - [198; 216) 'unknow...tion()': f64 - [222; 229) '&mut &c': &mut &f64 - [227; 229) '&c': &f64 - [228; 229) 'c': f64 - "### - ); -} - -#[test] -fn infer_self() { - assert_snapshot!( - infer(r#" -struct S; - -impl S { - fn test(&self) { - self; - } - fn test2(self: &Self) { - self; - } - fn test3() -> Self { - S {} - } - fn test4() -> Self { - Self {} - } -} -"#), - @r###" - [34; 38) 'self': &S - [40; 61) '{ ... }': () - [50; 54) 'self': &S - [75; 79) 'self': &S - [88; 109) '{ ... }': () - [98; 102) 'self': &S - [133; 153) '{ ... }': S - [143; 147) 'S {}': S - [177; 200) '{ ... }': S - [187; 194) 'Self {}': S - "### - ); -} - -#[test] -fn infer_binary_op() { - assert_snapshot!( - infer(r#" -fn f(x: bool) -> i32 { - 0i32 -} - -fn test() -> bool { - let x = a && b; - let y = true || false; - let z = x == y; - let t = x != y; - let minus_forty: isize = -40isize; - let h = minus_forty <= CONST_2; - let c = f(z || y) + 5; - let d = b; - let g = minus_forty ^= i; - let ten: usize = 10; - let ten_is_eleven = ten == some_num; - - ten < 3 -} -"#), - @r###" - [6; 7) 'x': bool - [22; 34) '{ 0i32 }': i32 - [28; 32) '0i32': i32 - [54; 370) '{ ... < 3 }': bool - [64; 65) 'x': bool - [68; 69) 'a': bool - [68; 74) 'a && b': bool - [73; 74) 'b': bool - [84; 85) 'y': bool - [88; 92) 'true': bool - [88; 101) 'true || false': bool - [96; 101) 'false': bool - [111; 112) 'z': bool - [115; 116) 'x': bool - [115; 121) 'x == y': bool - [120; 121) 'y': bool - [131; 132) 't': bool - [135; 136) 'x': bool - [135; 141) 'x != y': bool - [140; 141) 'y': bool - [151; 162) 'minus_forty': isize - [172; 180) '-40isize': isize - [173; 180) '40isize': isize - [190; 191) 'h': bool - [194; 205) 'minus_forty': isize - [194; 216) 'minus_...ONST_2': bool - [209; 216) 'CONST_2': isize - [226; 227) 'c': i32 - [230; 231) 'f': fn f(bool) -> i32 - [230; 239) 'f(z || y)': i32 - [230; 243) 'f(z || y) + 5': i32 - [232; 233) 'z': bool - [232; 238) 'z || y': bool - [237; 238) 'y': bool - [242; 243) '5': i32 - [253; 254) 'd': {unknown} - [257; 258) 'b': {unknown} - [268; 269) 'g': () - [272; 283) 'minus_forty': isize - [272; 288) 'minus_...y ^= i': () - [287; 288) 'i': isize - [298; 301) 'ten': usize - [311; 313) '10': usize - [323; 336) 'ten_is_eleven': bool - [339; 342) 'ten': usize - [339; 354) 'ten == some_num': bool - [346; 354) 'some_num': usize - [361; 364) 'ten': usize - [361; 368) 'ten < 3': bool - [367; 368) '3': usize - "### - ); -} - -#[test] -fn infer_field_autoderef() { - assert_snapshot!( - infer(r#" -struct A { - b: B, -} -struct B; - -fn test1(a: A) { - let a1 = a; - a1.b; - let a2 = &a; - a2.b; - let a3 = &mut a; - a3.b; - let a4 = &&&&&&&a; - a4.b; - let a5 = &mut &&mut &&mut a; - a5.b; -} - -fn test2(a1: *const A, a2: *mut A) { - a1.b; - a2.b; -} -"#), - @r###" - [44; 45) 'a': A - [50; 213) '{ ...5.b; }': () - [60; 62) 'a1': A - [65; 66) 'a': A - [72; 74) 'a1': A - [72; 76) 'a1.b': B - [86; 88) 'a2': &A - [91; 93) '&a': &A - [92; 93) 'a': A - [99; 101) 'a2': &A - [99; 103) 'a2.b': B - [113; 115) 'a3': &mut A - [118; 124) '&mut a': &mut A - [123; 124) 'a': A - [130; 132) 'a3': &mut A - [130; 134) 'a3.b': B - [144; 146) 'a4': &&&&&&&A - [149; 157) '&&&&&&&a': &&&&&&&A - [150; 157) '&&&&&&a': &&&&&&A - [151; 157) '&&&&&a': &&&&&A - [152; 157) '&&&&a': &&&&A - [153; 157) '&&&a': &&&A - [154; 157) '&&a': &&A - [155; 157) '&a': &A - [156; 157) 'a': A - [163; 165) 'a4': &&&&&&&A - [163; 167) 'a4.b': B - [177; 179) 'a5': &mut &&mut &&mut A - [182; 200) '&mut &...&mut a': &mut &&mut &&mut A - [187; 200) '&&mut &&mut a': &&mut &&mut A - [188; 200) '&mut &&mut a': &mut &&mut A - [193; 200) '&&mut a': &&mut A - [194; 200) '&mut a': &mut A - [199; 200) 'a': A - [206; 208) 'a5': &mut &&mut &&mut A - [206; 210) 'a5.b': B - [224; 226) 'a1': *const A - [238; 240) 'a2': *mut A - [250; 273) '{ ...2.b; }': () - [256; 258) 'a1': *const A - [256; 260) 'a1.b': B - [266; 268) 'a2': *mut A - [266; 270) 'a2.b': B - "### - ); -} - -#[test] -fn infer_argument_autoderef() { - assert_snapshot!( - infer(r#" -#[lang = "deref"] -pub trait Deref { - type Target; - fn deref(&self) -> &Self::Target; -} - -struct A(T); - -impl A { - fn foo(&self) -> &T { - &self.0 - } -} - -struct B(T); - -impl Deref for B { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -fn test() { - let t = A::foo(&&B(B(A(42)))); -} -"#), - @r###" - [68; 72) 'self': &Self - [139; 143) 'self': &A - [151; 174) '{ ... }': &T - [161; 168) '&self.0': &T - [162; 166) 'self': &A - [162; 168) 'self.0': T - [255; 259) 'self': &B - [278; 301) '{ ... }': &T - [288; 295) '&self.0': &T - [289; 293) 'self': &B - [289; 295) 'self.0': T - [315; 353) '{ ...))); }': () - [325; 326) 't': &i32 - [329; 335) 'A::foo': fn foo(&A) -> &T - [329; 350) 'A::foo...42))))': &i32 - [336; 349) '&&B(B(A(42)))': &&B>> - [337; 349) '&B(B(A(42)))': &B>> - [338; 339) 'B': B>>(T) -> B - [338; 349) 'B(B(A(42)))': B>> - [340; 341) 'B': B>(T) -> B - [340; 348) 'B(A(42))': B> - [342; 343) 'A': A(T) -> A - [342; 347) 'A(42)': A - [344; 346) '42': i32 - "### - ); -} - -#[test] -fn infer_method_argument_autoderef() { - assert_snapshot!( - infer(r#" -#[lang = "deref"] -pub trait Deref { - type Target; - fn deref(&self) -> &Self::Target; -} - -struct A(*mut T); - -impl A { - fn foo(&self, x: &A) -> &T { - &*x.0 - } -} - -struct B(T); - -impl Deref for B { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -fn test(a: A) { - let t = A(0 as *mut _).foo(&&B(B(a))); -} -"#), - @r###" - [68; 72) 'self': &Self - [144; 148) 'self': &A - [150; 151) 'x': &A - [166; 187) '{ ... }': &T - [176; 181) '&*x.0': &T - [177; 181) '*x.0': T - [178; 179) 'x': &A - [178; 181) 'x.0': *mut T - [268; 272) 'self': &B - [291; 314) '{ ... }': &T - [301; 308) '&self.0': &T - [302; 306) 'self': &B - [302; 308) 'self.0': T - [326; 327) 'a': A - [337; 383) '{ ...))); }': () - [347; 348) 't': &i32 - [351; 352) 'A': A(*mut T) -> A - [351; 365) 'A(0 as *mut _)': A - [351; 380) 'A(0 as...B(a)))': &i32 - [353; 354) '0': i32 - [353; 364) '0 as *mut _': *mut i32 - [370; 379) '&&B(B(a))': &&B>> - [371; 379) '&B(B(a))': &B>> - [372; 373) 'B': B>>(T) -> B - [372; 379) 'B(B(a))': B>> - [374; 375) 'B': B>(T) -> B - [374; 378) 'B(a)': B> - [376; 377) 'a': A - "### - ); -} - -#[test] -fn bug_484() { - assert_snapshot!( - infer(r#" -fn test() { - let x = if true {}; -} -"#), - @r###" - [11; 37) '{ l... {}; }': () - [20; 21) 'x': () - [24; 34) 'if true {}': () - [27; 31) 'true': bool - [32; 34) '{}': () - "### - ); -} - -#[test] -fn infer_in_elseif() { - assert_snapshot!( - infer(r#" -struct Foo { field: i32 } -fn main(foo: Foo) { - if true { - - } else if false { - foo.field - } -} -"#), - @r###" - [35; 38) 'foo': Foo - [45; 109) '{ ... } }': () - [51; 107) 'if tru... }': () - [54; 58) 'true': bool - [59; 67) '{ }': () - [73; 107) 'if fal... }': () - [76; 81) 'false': bool - [82; 107) '{ ... }': i32 - [92; 95) 'foo': Foo - [92; 101) 'foo.field': i32 - "### - ) -} - -#[test] -fn infer_if_match_with_return() { - assert_snapshot!( - infer(r#" -fn foo() { - let _x1 = if true { - 1 - } else { - return; - }; - let _x2 = if true { - 2 - } else { - return - }; - let _x3 = match true { - true => 3, - _ => { - return; - } - }; - let _x4 = match true { - true => 4, - _ => return - }; -}"#), - @r###" - [10; 323) '{ ... }; }': () - [20; 23) '_x1': i32 - [26; 80) 'if tru... }': i32 - [29; 33) 'true': bool - [34; 51) '{ ... }': i32 - [44; 45) '1': i32 - [57; 80) '{ ... }': ! - [67; 73) 'return': ! - [90; 93) '_x2': i32 - [96; 149) 'if tru... }': i32 - [99; 103) 'true': bool - [104; 121) '{ ... }': i32 - [114; 115) '2': i32 - [127; 149) '{ ... }': ! - [137; 143) 'return': ! - [159; 162) '_x3': i32 - [165; 247) 'match ... }': i32 - [171; 175) 'true': bool - [186; 190) 'true': bool - [194; 195) '3': i32 - [205; 206) '_': bool - [210; 241) '{ ... }': ! - [224; 230) 'return': ! - [257; 260) '_x4': i32 - [263; 320) 'match ... }': i32 - [269; 273) 'true': bool - [284; 288) 'true': bool - [292; 293) '4': i32 - [303; 304) '_': bool - [308; 314) 'return': ! - "### - ) -} - -#[test] -fn infer_inherent_method() { - assert_snapshot!( - infer(r#" -struct A; - -impl A { - fn foo(self, x: u32) -> i32 {} -} - -mod b { - impl super::A { - fn bar(&self, x: u64) -> i64 {} - } -} - -fn test(a: A) { - a.foo(1); - (&a).bar(1); - a.bar(1); -} -"#), - @r###" - [32; 36) 'self': A - [38; 39) 'x': u32 - [53; 55) '{}': () - [103; 107) 'self': &A - [109; 110) 'x': u64 - [124; 126) '{}': () - [144; 145) 'a': A - [150; 198) '{ ...(1); }': () - [156; 157) 'a': A - [156; 164) 'a.foo(1)': i32 - [162; 163) '1': u32 - [170; 181) '(&a).bar(1)': i64 - [171; 173) '&a': &A - [172; 173) 'a': A - [179; 180) '1': u64 - [187; 188) 'a': A - [187; 195) 'a.bar(1)': i64 - [193; 194) '1': u64 - "### - ); -} - -#[test] -fn infer_inherent_method_str() { - assert_snapshot!( - infer(r#" -#[lang = "str"] -impl str { - fn foo(&self) -> i32 {} -} - -fn test() { - "foo".foo(); -} -"#), - @r###" - [40; 44) 'self': &str - [53; 55) '{}': () - [69; 89) '{ ...o(); }': () - [75; 80) '"foo"': &str - [75; 86) '"foo".foo()': i32 - "### - ); -} - -#[test] -fn infer_tuple() { - assert_snapshot!( - infer(r#" -fn test(x: &str, y: isize) { - let a: (u32, &str) = (1, "a"); - let b = (a, x); - let c = (y, x); - let d = (c, x); - let e = (1, "e"); - let f = (e, "d"); -} -"#), - @r###" - [9; 10) 'x': &str - [18; 19) 'y': isize - [28; 170) '{ ...d"); }': () - [38; 39) 'a': (u32, &str) - [55; 63) '(1, "a")': (u32, &str) - [56; 57) '1': u32 - [59; 62) '"a"': &str - [73; 74) 'b': ((u32, &str), &str) - [77; 83) '(a, x)': ((u32, &str), &str) - [78; 79) 'a': (u32, &str) - [81; 82) 'x': &str - [93; 94) 'c': (isize, &str) - [97; 103) '(y, x)': (isize, &str) - [98; 99) 'y': isize - [101; 102) 'x': &str - [113; 114) 'd': ((isize, &str), &str) - [117; 123) '(c, x)': ((isize, &str), &str) - [118; 119) 'c': (isize, &str) - [121; 122) 'x': &str - [133; 134) 'e': (i32, &str) - [137; 145) '(1, "e")': (i32, &str) - [138; 139) '1': i32 - [141; 144) '"e"': &str - [155; 156) 'f': ((i32, &str), &str) - [159; 167) '(e, "d")': ((i32, &str), &str) - [160; 161) 'e': (i32, &str) - [163; 166) '"d"': &str - "### - ); -} - -#[test] -fn infer_array() { - assert_snapshot!( - infer(r#" -fn test(x: &str, y: isize) { - let a = [x]; - let b = [a, a]; - let c = [b, b]; - - let d = [y, 1, 2, 3]; - let d = [1, y, 2, 3]; - let e = [y]; - let f = [d, d]; - let g = [e, e]; - - let h = [1, 2]; - let i = ["a", "b"]; - - let b = [a, ["b"]]; - let x: [u8; 0] = []; -} -"#), - @r###" - [9; 10) 'x': &str - [18; 19) 'y': isize - [28; 293) '{ ... []; }': () - [38; 39) 'a': [&str;_] - [42; 45) '[x]': [&str;_] - [43; 44) 'x': &str - [55; 56) 'b': [[&str;_];_] - [59; 65) '[a, a]': [[&str;_];_] - [60; 61) 'a': [&str;_] - [63; 64) 'a': [&str;_] - [75; 76) 'c': [[[&str;_];_];_] - [79; 85) '[b, b]': [[[&str;_];_];_] - [80; 81) 'b': [[&str;_];_] - [83; 84) 'b': [[&str;_];_] - [96; 97) 'd': [isize;_] - [100; 112) '[y, 1, 2, 3]': [isize;_] - [101; 102) 'y': isize - [104; 105) '1': isize - [107; 108) '2': isize - [110; 111) '3': isize - [122; 123) 'd': [isize;_] - [126; 138) '[1, y, 2, 3]': [isize;_] - [127; 128) '1': isize - [130; 131) 'y': isize - [133; 134) '2': isize - [136; 137) '3': isize - [148; 149) 'e': [isize;_] - [152; 155) '[y]': [isize;_] - [153; 154) 'y': isize - [165; 166) 'f': [[isize;_];_] - [169; 175) '[d, d]': [[isize;_];_] - [170; 171) 'd': [isize;_] - [173; 174) 'd': [isize;_] - [185; 186) 'g': [[isize;_];_] - [189; 195) '[e, e]': [[isize;_];_] - [190; 191) 'e': [isize;_] - [193; 194) 'e': [isize;_] - [206; 207) 'h': [i32;_] - [210; 216) '[1, 2]': [i32;_] - [211; 212) '1': i32 - [214; 215) '2': i32 - [226; 227) 'i': [&str;_] - [230; 240) '["a", "b"]': [&str;_] - [231; 234) '"a"': &str - [236; 239) '"b"': &str - [251; 252) 'b': [[&str;_];_] - [255; 265) '[a, ["b"]]': [[&str;_];_] - [256; 257) 'a': [&str;_] - [259; 264) '["b"]': [&str;_] - [260; 263) '"b"': &str - [275; 276) 'x': [u8;_] - [288; 290) '[]': [u8;_] - "### - ); -} - -#[test] -fn infer_pattern() { - assert_snapshot!( - infer(r#" -fn test(x: &i32) { - let y = x; - let &z = x; - let a = z; - let (c, d) = (1, "hello"); - - for (e, f) in some_iter { - let g = e; - } - - if let [val] = opt { - let h = val; - } - - let lambda = |a: u64, b, c: i32| { a + b; c }; - - let ref ref_to_x = x; - let mut mut_x = x; - let ref mut mut_ref_to_x = x; - let k = mut_ref_to_x; -} -"#), - @r###" - [9; 10) 'x': &i32 - [18; 369) '{ ...o_x; }': () - [28; 29) 'y': &i32 - [32; 33) 'x': &i32 - [43; 45) '&z': &i32 - [44; 45) 'z': i32 - [48; 49) 'x': &i32 - [59; 60) 'a': i32 - [63; 64) 'z': i32 - [74; 80) '(c, d)': (i32, &str) - [75; 76) 'c': i32 - [78; 79) 'd': &str - [83; 95) '(1, "hello")': (i32, &str) - [84; 85) '1': i32 - [87; 94) '"hello"': &str - [102; 152) 'for (e... }': () - [106; 112) '(e, f)': ({unknown}, {unknown}) - [107; 108) 'e': {unknown} - [110; 111) 'f': {unknown} - [116; 125) 'some_iter': {unknown} - [126; 152) '{ ... }': () - [140; 141) 'g': {unknown} - [144; 145) 'e': {unknown} - [158; 205) 'if let... }': () - [165; 170) '[val]': {unknown} - [173; 176) 'opt': {unknown} - [177; 205) '{ ... }': () - [191; 192) 'h': {unknown} - [195; 198) 'val': {unknown} - [215; 221) 'lambda': |u64, u64, i32| -> i32 - [224; 256) '|a: u6...b; c }': |u64, u64, i32| -> i32 - [225; 226) 'a': u64 - [233; 234) 'b': u64 - [236; 237) 'c': i32 - [244; 256) '{ a + b; c }': i32 - [246; 247) 'a': u64 - [246; 251) 'a + b': u64 - [250; 251) 'b': u64 - [253; 254) 'c': i32 - [267; 279) 'ref ref_to_x': &&i32 - [282; 283) 'x': &i32 - [293; 302) 'mut mut_x': &i32 - [305; 306) 'x': &i32 - [316; 336) 'ref mu...f_to_x': &mut &i32 - [339; 340) 'x': &i32 - [350; 351) 'k': &mut &i32 - [354; 366) 'mut_ref_to_x': &mut &i32 - "### - ); -} - -#[test] -fn infer_pattern_match_ergonomics() { - assert_snapshot!( - infer(r#" -struct A(T); - -fn test() { - let A(n) = &A(1); - let A(n) = &mut A(1); -} -"#), - @r###" - [28; 79) '{ ...(1); }': () - [38; 42) 'A(n)': A - [40; 41) 'n': &i32 - [45; 50) '&A(1)': &A - [46; 47) 'A': A(T) -> A - [46; 50) 'A(1)': A - [48; 49) '1': i32 - [60; 64) 'A(n)': A - [62; 63) 'n': &mut i32 - [67; 76) '&mut A(1)': &mut A - [72; 73) 'A': A(T) -> A - [72; 76) 'A(1)': A - [74; 75) '1': i32 - "### - ); -} - -#[test] -fn infer_pattern_match_ergonomics_ref() { - covers!(match_ergonomics_ref); - assert_snapshot!( - infer(r#" -fn test() { - let v = &(1, &2); - let (_, &w) = v; -} -"#), - @r###" - [11; 57) '{ ...= v; }': () - [21; 22) 'v': &(i32, &i32) - [25; 33) '&(1, &2)': &(i32, &i32) - [26; 33) '(1, &2)': (i32, &i32) - [27; 28) '1': i32 - [30; 32) '&2': &i32 - [31; 32) '2': i32 - [43; 50) '(_, &w)': (i32, &i32) - [44; 45) '_': i32 - [47; 49) '&w': &i32 - [48; 49) 'w': i32 - [53; 54) 'v': &(i32, &i32) - "### - ); -} - -#[test] -fn infer_adt_pattern() { - assert_snapshot!( - infer(r#" -enum E { - A { x: usize }, - B -} - -struct S(u32, E); - -fn test() { - let e = E::A { x: 3 }; - - let S(y, z) = foo; - let E::A { x: new_var } = e; - - match e { - E::A { x } => x, - E::B if foo => 1, - E::B => 10, - }; - - let ref d @ E::A { .. } = e; - d; -} -"#), - @r###" - [68; 289) '{ ... d; }': () - [78; 79) 'e': E - [82; 95) 'E::A { x: 3 }': E - [92; 93) '3': usize - [106; 113) 'S(y, z)': S - [108; 109) 'y': u32 - [111; 112) 'z': E - [116; 119) 'foo': S - [129; 148) 'E::A {..._var }': E - [139; 146) 'new_var': usize - [151; 152) 'e': E - [159; 245) 'match ... }': usize - [165; 166) 'e': E - [177; 187) 'E::A { x }': E - [184; 185) 'x': usize - [191; 192) 'x': usize - [202; 206) 'E::B': E - [210; 213) 'foo': bool - [217; 218) '1': usize - [228; 232) 'E::B': E - [236; 238) '10': usize - [256; 275) 'ref d ...{ .. }': &E - [264; 275) 'E::A { .. }': E - [278; 279) 'e': E - [285; 286) 'd': &E - "### - ); -} - -#[test] -fn infer_struct_generics() { - assert_snapshot!( - infer(r#" -struct A { - x: T, -} - -fn test(a1: A, i: i32) { - a1.x; - let a2 = A { x: i }; - a2.x; - let a3 = A:: { x: 1 }; - a3.x; -} -"#), - @r###" - [36; 38) 'a1': A - [48; 49) 'i': i32 - [56; 147) '{ ...3.x; }': () - [62; 64) 'a1': A - [62; 66) 'a1.x': u32 - [76; 78) 'a2': A - [81; 91) 'A { x: i }': A - [88; 89) 'i': i32 - [97; 99) 'a2': A - [97; 101) 'a2.x': i32 - [111; 113) 'a3': A - [116; 134) 'A:: - [131; 132) '1': i128 - [140; 142) 'a3': A - [140; 144) 'a3.x': i128 - "### - ); -} - -#[test] -fn infer_tuple_struct_generics() { - assert_snapshot!( - infer(r#" -struct A(T); -enum Option { Some(T), None } -use Option::*; - -fn test() { - A(42); - A(42u128); - Some("x"); - Option::Some("x"); - None; - let x: Option = None; -} -"#), - @r###" - [76; 184) '{ ...one; }': () - [82; 83) 'A': A(T) -> A - [82; 87) 'A(42)': A - [84; 86) '42': i32 - [93; 94) 'A': A(T) -> A - [93; 102) 'A(42u128)': A - [95; 101) '42u128': u128 - [108; 112) 'Some': Some<&str>(T) -> Option - [108; 117) 'Some("x")': Option<&str> - [113; 116) '"x"': &str - [123; 135) 'Option::Some': Some<&str>(T) -> Option - [123; 140) 'Option...e("x")': Option<&str> - [136; 139) '"x"': &str - [146; 150) 'None': Option<{unknown}> - [160; 161) 'x': Option - [177; 181) 'None': Option - "### - ); -} - -#[test] -fn infer_generics_in_patterns() { - assert_snapshot!( - infer(r#" -struct A { - x: T, -} - -enum Option { - Some(T), - None, -} - -fn test(a1: A, o: Option) { - let A { x: x2 } = a1; - let A:: { x: x3 } = A { x: 1 }; - match o { - Option::Some(t) => t, - _ => 1, - }; -} -"#), - @r###" - [79; 81) 'a1': A - [91; 92) 'o': Option - [107; 244) '{ ... }; }': () - [117; 128) 'A { x: x2 }': A - [124; 126) 'x2': u32 - [131; 133) 'a1': A - [143; 161) 'A:: - [157; 159) 'x3': i64 - [164; 174) 'A { x: 1 }': A - [171; 172) '1': i64 - [180; 241) 'match ... }': u64 - [186; 187) 'o': Option - [198; 213) 'Option::Some(t)': Option - [211; 212) 't': u64 - [217; 218) 't': u64 - [228; 229) '_': Option - [233; 234) '1': u64 - "### - ); -} - -#[test] -fn infer_function_generics() { - assert_snapshot!( - infer(r#" -fn id(t: T) -> T { t } - -fn test() { - id(1u32); - id::(1); - let x: u64 = id(1); -} -"#), - @r###" - [10; 11) 't': T - [21; 26) '{ t }': T - [23; 24) 't': T - [38; 98) '{ ...(1); }': () - [44; 46) 'id': fn id(T) -> T - [44; 52) 'id(1u32)': u32 - [47; 51) '1u32': u32 - [58; 68) 'id::': fn id(T) -> T - [58; 71) 'id::(1)': i128 - [69; 70) '1': i128 - [81; 82) 'x': u64 - [90; 92) 'id': fn id(T) -> T - [90; 95) 'id(1)': u64 - [93; 94) '1': u64 - "### - ); -} - -#[test] -fn infer_impl_generics() { - assert_snapshot!( - infer(r#" -struct A { - x: T1, - y: T2, -} -impl A { - fn x(self) -> X { - self.x - } - fn y(self) -> Y { - self.y - } - fn z(self, t: T) -> (X, Y, T) { - (self.x, self.y, t) - } -} - -fn test() -> i128 { - let a = A { x: 1u64, y: 1i64 }; - a.x(); - a.y(); - a.z(1i128); - a.z::(1); -} -"#), - @r###" - [74; 78) 'self': A - [85; 107) '{ ... }': X - [95; 99) 'self': A - [95; 101) 'self.x': X - [117; 121) 'self': A - [128; 150) '{ ... }': Y - [138; 142) 'self': A - [138; 144) 'self.y': Y - [163; 167) 'self': A - [169; 170) 't': T - [188; 223) '{ ... }': (X, Y, T) - [198; 217) '(self.....y, t)': (X, Y, T) - [199; 203) 'self': A - [199; 205) 'self.x': X - [207; 211) 'self': A - [207; 213) 'self.y': Y - [215; 216) 't': T - [245; 342) '{ ...(1); }': () - [255; 256) 'a': A - [259; 281) 'A { x:...1i64 }': A - [266; 270) '1u64': u64 - [275; 279) '1i64': i64 - [287; 288) 'a': A - [287; 292) 'a.x()': u64 - [298; 299) 'a': A - [298; 303) 'a.y()': i64 - [309; 310) 'a': A - [309; 319) 'a.z(1i128)': (u64, i64, i128) - [313; 318) '1i128': i128 - [325; 326) 'a': A - [325; 339) 'a.z::(1)': (u64, i64, u128) - [337; 338) '1': u128 - "### - ); -} - -#[test] -fn infer_impl_generics_with_autoderef() { - assert_snapshot!( - infer(r#" -enum Option { - Some(T), - None, -} -impl Option { - fn as_ref(&self) -> Option<&T> {} -} -fn test(o: Option) { - (&o).as_ref(); - o.as_ref(); -} -"#), - @r###" - [78; 82) 'self': &Option - [98; 100) '{}': () - [111; 112) 'o': Option - [127; 165) '{ ...f(); }': () - [133; 146) '(&o).as_ref()': Option<&u32> - [134; 136) '&o': &Option - [135; 136) 'o': Option - [152; 153) 'o': Option - [152; 162) 'o.as_ref()': Option<&u32> - "### - ); -} - -#[test] -fn infer_generic_chain() { - assert_snapshot!( - infer(r#" -struct A { - x: T, -} -impl A { - fn x(self) -> T2 { - self.x - } -} -fn id(t: T) -> T { t } - -fn test() -> i128 { - let x = 1; - let y = id(x); - let a = A { x: id(y) }; - let z = id(a.x); - let b = A { x: z }; - b.x() -} -"#), - @r###" - [53; 57) 'self': A - [65; 87) '{ ... }': T2 - [75; 79) 'self': A - [75; 81) 'self.x': T2 - [99; 100) 't': T - [110; 115) '{ t }': T - [112; 113) 't': T - [135; 261) '{ ....x() }': i128 - [146; 147) 'x': i128 - [150; 151) '1': i128 - [162; 163) 'y': i128 - [166; 168) 'id': fn id(T) -> T - [166; 171) 'id(x)': i128 - [169; 170) 'x': i128 - [182; 183) 'a': A - [186; 200) 'A { x: id(y) }': A - [193; 195) 'id': fn id(T) -> T - [193; 198) 'id(y)': i128 - [196; 197) 'y': i128 - [211; 212) 'z': i128 - [215; 217) 'id': fn id(T) -> T - [215; 222) 'id(a.x)': i128 - [218; 219) 'a': A - [218; 221) 'a.x': i128 - [233; 234) 'b': A - [237; 247) 'A { x: z }': A - [244; 245) 'z': i128 - [254; 255) 'b': A - [254; 259) 'b.x()': i128 - "### - ); -} - -#[test] -fn infer_associated_const() { - assert_snapshot!( - infer(r#" -struct Struct; - -impl Struct { - const FOO: u32 = 1; -} - -enum Enum {} - -impl Enum { - const BAR: u32 = 2; -} - -trait Trait { - const ID: u32; -} - -struct TraitTest; - -impl Trait for TraitTest { - const ID: u32 = 5; -} - -fn test() { - let x = Struct::FOO; - let y = Enum::BAR; - let z = TraitTest::ID; -} -"#), - @r###" - [52; 53) '1': u32 - [105; 106) '2': u32 - [213; 214) '5': u32 - [229; 307) '{ ...:ID; }': () - [239; 240) 'x': u32 - [243; 254) 'Struct::FOO': u32 - [264; 265) 'y': u32 - [268; 277) 'Enum::BAR': u32 - [287; 288) 'z': u32 - [291; 304) 'TraitTest::ID': u32 - "### - ); -} - -#[test] -fn infer_associated_method_struct() { - assert_snapshot!( - infer(r#" -struct A { x: u32 } - -impl A { - fn new() -> A { - A { x: 0 } - } -} -fn test() { - let a = A::new(); - a.x; -} -"#), - @r###" - [49; 75) '{ ... }': A - [59; 69) 'A { x: 0 }': A - [66; 67) '0': u32 - [88; 122) '{ ...a.x; }': () - [98; 99) 'a': A - [102; 108) 'A::new': fn new() -> A - [102; 110) 'A::new()': A - [116; 117) 'a': A - [116; 119) 'a.x': u32 - "### - ); -} - -#[test] -fn infer_associated_method_enum() { - assert_snapshot!( - infer(r#" -enum A { B, C } - -impl A { - pub fn b() -> A { - A::B - } - pub fn c() -> A { - A::C - } -} -fn test() { - let a = A::b(); - a; - let c = A::c(); - c; -} -"#), - @r###" - [47; 67) '{ ... }': A - [57; 61) 'A::B': A - [88; 108) '{ ... }': A - [98; 102) 'A::C': A - [121; 178) '{ ... c; }': () - [131; 132) 'a': A - [135; 139) 'A::b': fn b() -> A - [135; 141) 'A::b()': A - [147; 148) 'a': A - [158; 159) 'c': A - [162; 166) 'A::c': fn c() -> A - [162; 168) 'A::c()': A - [174; 175) 'c': A - "### - ); -} - -#[test] -fn infer_associated_method_with_modules() { - assert_snapshot!( - infer(r#" -mod a { - struct A; - impl A { pub fn thing() -> A { A {} }} -} - -mod b { - struct B; - impl B { pub fn thing() -> u32 { 99 }} - - mod c { - struct C; - impl C { pub fn thing() -> C { C {} }} - } -} -use b::c; - -fn test() { - let x = a::A::thing(); - let y = b::B::thing(); - let z = c::C::thing(); -} -"#), - @r###" - [56; 64) '{ A {} }': A - [58; 62) 'A {}': A - [126; 132) '{ 99 }': u32 - [128; 130) '99': u32 - [202; 210) '{ C {} }': C - [204; 208) 'C {}': C - [241; 325) '{ ...g(); }': () - [251; 252) 'x': A - [255; 266) 'a::A::thing': fn thing() -> A - [255; 268) 'a::A::thing()': A - [278; 279) 'y': u32 - [282; 293) 'b::B::thing': fn thing() -> u32 - [282; 295) 'b::B::thing()': u32 - [305; 306) 'z': C - [309; 320) 'c::C::thing': fn thing() -> C - [309; 322) 'c::C::thing()': C - "### - ); -} - -#[test] -fn infer_associated_method_generics() { - assert_snapshot!( - infer(r#" -struct Gen { - val: T -} - -impl Gen { - pub fn make(val: T) -> Gen { - Gen { val } - } -} - -fn test() { - let a = Gen::make(0u32); -} -"#), - @r###" - [64; 67) 'val': T - [82; 109) '{ ... }': Gen - [92; 103) 'Gen { val }': Gen - [98; 101) 'val': T - [123; 155) '{ ...32); }': () - [133; 134) 'a': Gen - [137; 146) 'Gen::make': fn make(T) -> Gen - [137; 152) 'Gen::make(0u32)': Gen - [147; 151) '0u32': u32 - "### - ); -} - -#[test] -fn infer_associated_method_generics_with_default_param() { - assert_snapshot!( - infer(r#" -struct Gen { - val: T -} - -impl Gen { - pub fn make() -> Gen { - loop { } - } -} - -fn test() { - let a = Gen::make(); -} -"#), - @r###" - [80; 104) '{ ... }': Gen - [90; 98) 'loop { }': ! - [95; 98) '{ }': () - [118; 146) '{ ...e(); }': () - [128; 129) 'a': Gen - [132; 141) 'Gen::make': fn make() -> Gen - [132; 143) 'Gen::make()': Gen - "### - ); -} - -#[test] -fn infer_associated_method_generics_with_default_tuple_param() { - let t = type_at( - r#" -//- /main.rs -struct Gen { - val: T -} - -impl Gen { - pub fn make() -> Gen { - loop { } - } -} - -fn test() { - let a = Gen::make(); - a.val<|>; -} -"#, - ); - assert_eq!(t, "()"); -} - -#[test] -fn infer_associated_method_generics_without_args() { - assert_snapshot!( - infer(r#" -struct Gen { - val: T -} - -impl Gen { - pub fn make() -> Gen { - loop { } - } -} - -fn test() { - let a = Gen::::make(); -} -"#), - @r###" - [76; 100) '{ ... }': Gen - [86; 94) 'loop { }': ! - [91; 94) '{ }': () - [114; 149) '{ ...e(); }': () - [124; 125) 'a': Gen - [128; 144) 'Gen::<...::make': fn make() -> Gen - [128; 146) 'Gen::<...make()': Gen - "### - ); -} - -#[test] -fn infer_associated_method_generics_2_type_params_without_args() { - assert_snapshot!( - infer(r#" -struct Gen { - val: T, - val2: U, -} - -impl Gen { - pub fn make() -> Gen { - loop { } - } -} - -fn test() { - let a = Gen::::make(); -} -"#), - @r###" - [102; 126) '{ ... }': Gen - [112; 120) 'loop { }': ! - [117; 120) '{ }': () - [140; 180) '{ ...e(); }': () - [150; 151) 'a': Gen - [154; 175) 'Gen::<...::make': fn make() -> Gen - [154; 177) 'Gen::<...make()': Gen - "### - ); -} - -#[test] -fn infer_type_alias() { - assert_snapshot!( - infer(r#" -struct A { x: X, y: Y } -type Foo = A; -type Bar = A; -type Baz = A; -fn test(x: Foo, y: Bar<&str>, z: Baz) { - x.x; - x.y; - y.x; - y.y; - z.x; - z.y; -} -"#), - @r###" - [116; 117) 'x': A - [124; 125) 'y': A<&str, u128> - [138; 139) 'z': A - [154; 211) '{ ...z.y; }': () - [160; 161) 'x': A - [160; 163) 'x.x': u32 - [169; 170) 'x': A - [169; 172) 'x.y': i128 - [178; 179) 'y': A<&str, u128> - [178; 181) 'y.x': &str - [187; 188) 'y': A<&str, u128> - [187; 190) 'y.y': u128 - [196; 197) 'z': A - [196; 199) 'z.x': u8 - [205; 206) 'z': A - [205; 208) 'z.y': i8 - "### - ) -} - -#[test] -fn recursive_type_alias() { - assert_snapshot!( - infer(r#" -struct A {} -type Foo = Foo; -type Bar = A; -fn test(x: Foo) {} -"#), - @r###" - [59; 60) 'x': {unknown} - [67; 69) '{}': () - "### - ) -} - -#[test] -fn no_panic_on_field_of_enum() { - assert_snapshot!( - infer(r#" -enum X {} - -fn test(x: X) { - x.some_field; -} -"#), - @r###" - [20; 21) 'x': X - [26; 47) '{ ...eld; }': () - [32; 33) 'x': X - [32; 44) 'x.some_field': {unknown} - "### - ); -} - -#[test] -fn bug_585() { - assert_snapshot!( - infer(r#" -fn test() { - X {}; - match x { - A::B {} => (), - A::Y() => (), - } -} -"#), - @r###" - [11; 89) '{ ... } }': () - [17; 21) 'X {}': {unknown} - [27; 87) 'match ... }': () - [33; 34) 'x': {unknown} - [45; 52) 'A::B {}': {unknown} - [56; 58) '()': () - [68; 74) 'A::Y()': {unknown} - [78; 80) '()': () - "### - ); -} - -#[test] -fn bug_651() { - assert_snapshot!( - infer(r#" -fn quux() { - let y = 92; - 1 + y; -} -"#), - @r###" - [11; 41) '{ ...+ y; }': () - [21; 22) 'y': i32 - [25; 27) '92': i32 - [33; 34) '1': i32 - [33; 38) '1 + y': i32 - [37; 38) 'y': i32 - "### - ); -} - -#[test] -fn recursive_vars() { - covers!(type_var_cycles_resolve_completely); - covers!(type_var_cycles_resolve_as_possible); - assert_snapshot!( - infer(r#" -fn test() { - let y = unknown; - [y, &y]; -} -"#), - @r###" - [11; 48) '{ ...&y]; }': () - [21; 22) 'y': &{unknown} - [25; 32) 'unknown': &{unknown} - [38; 45) '[y, &y]': [&&{unknown};_] - [39; 40) 'y': &{unknown} - [42; 44) '&y': &&{unknown} - [43; 44) 'y': &{unknown} - "### - ); -} - -#[test] -fn recursive_vars_2() { - covers!(type_var_cycles_resolve_completely); - covers!(type_var_cycles_resolve_as_possible); - assert_snapshot!( - infer(r#" -fn test() { - let x = unknown; - let y = unknown; - [(x, y), (&y, &x)]; -} -"#), - @r###" - [11; 80) '{ ...x)]; }': () - [21; 22) 'x': &&{unknown} - [25; 32) 'unknown': &&{unknown} - [42; 43) 'y': &&{unknown} - [46; 53) 'unknown': &&{unknown} - [59; 77) '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown});_] - [60; 66) '(x, y)': (&&&{unknown}, &&&{unknown}) - [61; 62) 'x': &&{unknown} - [64; 65) 'y': &&{unknown} - [68; 76) '(&y, &x)': (&&&{unknown}, &&&{unknown}) - [69; 71) '&y': &&&{unknown} - [70; 71) 'y': &&{unknown} - [73; 75) '&x': &&&{unknown} - [74; 75) 'x': &&{unknown} - "### - ); -} - -#[test] -fn infer_type_param() { - assert_snapshot!( - infer(r#" -fn id(x: T) -> T { - x -} - -fn clone(x: &T) -> T { - *x -} - -fn test() { - let y = 10u32; - id(y); - let x: bool = clone(z); - id::(1); -} -"#), - @r###" - [10; 11) 'x': T - [21; 30) '{ x }': T - [27; 28) 'x': T - [44; 45) 'x': &T - [56; 66) '{ *x }': T - [62; 64) '*x': T - [63; 64) 'x': &T - [78; 158) '{ ...(1); }': () - [88; 89) 'y': u32 - [92; 97) '10u32': u32 - [103; 105) 'id': fn id(T) -> T - [103; 108) 'id(y)': u32 - [106; 107) 'y': u32 - [118; 119) 'x': bool - [128; 133) 'clone': fn clone(&T) -> T - [128; 136) 'clone(z)': bool - [134; 135) 'z': &bool - [142; 152) 'id::': fn id(T) -> T - [142; 155) 'id::(1)': i128 - [153; 154) '1': i128 - "### - ); -} - -#[test] -fn infer_std_crash_1() { - // caused stack overflow, taken from std - assert_snapshot!( - infer(r#" -enum Maybe { - Real(T), - Fake, -} - -fn write() { - match something_unknown { - Maybe::Real(ref mut something) => (), - } -} -"#), - @r###" - [54; 139) '{ ... } }': () - [60; 137) 'match ... }': () - [66; 83) 'someth...nknown': Maybe<{unknown}> - [94; 124) 'Maybe:...thing)': Maybe<{unknown}> - [106; 123) 'ref mu...ething': &mut {unknown} - [128; 130) '()': () - "### - ); -} - -#[test] -fn infer_std_crash_2() { - covers!(type_var_resolves_to_int_var); - // caused "equating two type variables, ...", taken from std - assert_snapshot!( - infer(r#" -fn test_line_buffer() { - &[0, b'\n', 1, b'\n']; -} -"#), - @r###" - [23; 53) '{ ...n']; }': () - [29; 50) '&[0, b...b'\n']': &[u8;_] - [30; 50) '[0, b'...b'\n']': [u8;_] - [31; 32) '0': u8 - [34; 39) 'b'\n'': u8 - [41; 42) '1': u8 - [44; 49) 'b'\n'': u8 - "### - ); -} - -#[test] -fn infer_std_crash_3() { - // taken from rustc - assert_snapshot!( - infer(r#" -pub fn compute() { - match nope!() { - SizeSkeleton::Pointer { non_zero: true, tail } => {} - } -} -"#), - @r###" - [18; 108) '{ ... } }': () - [24; 106) 'match ... }': () - [30; 37) 'nope!()': {unknown} - [48; 94) 'SizeSk...tail }': {unknown} - [82; 86) 'true': {unknown} - [88; 92) 'tail': {unknown} - [98; 100) '{}': () - "### - ); -} - -#[test] -fn infer_std_crash_4() { - // taken from rustc - assert_snapshot!( - infer(r#" -pub fn primitive_type() { - match *self { - BorrowedRef { type_: Primitive(p), ..} => {}, - } -} -"#), - @r###" - [25; 106) '{ ... } }': () - [31; 104) 'match ... }': () - [37; 42) '*self': {unknown} - [38; 42) 'self': {unknown} - [53; 91) 'Borrow...), ..}': {unknown} - [74; 86) 'Primitive(p)': {unknown} - [84; 85) 'p': {unknown} - [95; 97) '{}': () - "### - ); -} - -#[test] -fn infer_std_crash_5() { - // taken from rustc - assert_snapshot!( - infer(r#" -fn extra_compiler_flags() { - for content in doesnt_matter { - let name = if doesnt_matter { - first - } else { - &content - }; - - let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { - name - } else { - content - }; - } -} -"#), - @r###" - [27; 323) '{ ... } }': () - [33; 321) 'for co... }': () - [37; 44) 'content': &{unknown} - [48; 61) 'doesnt_matter': {unknown} - [62; 321) '{ ... }': () - [76; 80) 'name': &&{unknown} - [83; 167) 'if doe... }': &&{unknown} - [86; 99) 'doesnt_matter': bool - [100; 129) '{ ... }': &&{unknown} - [114; 119) 'first': &&{unknown} - [135; 167) '{ ... }': &&{unknown} - [149; 157) '&content': &&{unknown} - [150; 157) 'content': &{unknown} - [182; 189) 'content': &{unknown} - [192; 314) 'if ICE... }': &{unknown} - [195; 232) 'ICE_RE..._VALUE': {unknown} - [195; 248) 'ICE_RE...&name)': bool - [242; 247) '&name': &&&{unknown} - [243; 247) 'name': &&{unknown} - [249; 277) '{ ... }': &&{unknown} - [263; 267) 'name': &&{unknown} - [283; 314) '{ ... }': &{unknown} - [297; 304) 'content': &{unknown} - "### - ); -} - -#[test] -fn infer_nested_generics_crash() { - // another crash found typechecking rustc - assert_snapshot!( - infer(r#" -struct Canonical { - value: V, -} -struct QueryResponse { - value: V, -} -fn test(query_response: Canonical>) { - &query_response.value; -} -"#), - @r###" - [92; 106) 'query_response': Canonical> - [137; 167) '{ ...lue; }': () - [143; 164) '&query....value': &QueryResponse - [144; 158) 'query_response': Canonical> - [144; 164) 'query_....value': QueryResponse - "### - ); -} - -#[test] -fn bug_1030() { - assert_snapshot!(infer(r#" -struct HashSet; -struct FxHasher; -type FxHashSet = HashSet; - -impl HashSet { - fn default() -> HashSet {} -} - -pub fn main_loop() { - FxHashSet::default(); -} -"#), - @r###" - [144; 146) '{}': () - [169; 198) '{ ...t(); }': () - [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet - [175; 195) 'FxHash...ault()': HashSet<{unknown}, FxHasher> - "### - ); -} - -#[test] -fn cross_crate_associated_method_call() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs crate:main deps:other_crate -fn test() { - let x = other_crate::foo::S::thing(); - x<|>; -} - -//- /lib.rs crate:other_crate -mod foo { - struct S; - impl S { - fn thing() -> i128 {} - } -} -"#, - ); - assert_eq!("i128", type_at_pos(&db, pos)); -} - -#[test] -fn infer_const() { - assert_snapshot!( - infer(r#" -struct Foo; -impl Foo { const ASSOC_CONST: u32 = 0; } -const GLOBAL_CONST: u32 = 101; -fn test() { - const LOCAL_CONST: u32 = 99; - let x = LOCAL_CONST; - let z = GLOBAL_CONST; - let id = Foo::ASSOC_CONST; -} -"#), - @r###" - [49; 50) '0': u32 - [80; 83) '101': u32 - [95; 213) '{ ...NST; }': () - [138; 139) 'x': {unknown} - [142; 153) 'LOCAL_CONST': {unknown} - [163; 164) 'z': u32 - [167; 179) 'GLOBAL_CONST': u32 - [189; 191) 'id': u32 - [194; 210) 'Foo::A..._CONST': u32 - "### - ); -} - -#[test] -fn infer_static() { - assert_snapshot!( - infer(r#" -static GLOBAL_STATIC: u32 = 101; -static mut GLOBAL_STATIC_MUT: u32 = 101; -fn test() { - static LOCAL_STATIC: u32 = 99; - static mut LOCAL_STATIC_MUT: u32 = 99; - let x = LOCAL_STATIC; - let y = LOCAL_STATIC_MUT; - let z = GLOBAL_STATIC; - let w = GLOBAL_STATIC_MUT; -} -"#), - @r###" - [29; 32) '101': u32 - [70; 73) '101': u32 - [85; 280) '{ ...MUT; }': () - [173; 174) 'x': {unknown} - [177; 189) 'LOCAL_STATIC': {unknown} - [199; 200) 'y': {unknown} - [203; 219) 'LOCAL_...IC_MUT': {unknown} - [229; 230) 'z': u32 - [233; 246) 'GLOBAL_STATIC': u32 - [256; 257) 'w': u32 - [260; 277) 'GLOBAL...IC_MUT': u32 - "### - ); -} - -#[test] -fn infer_trait_method_simple() { - // the trait implementation is intentionally incomplete -- it shouldn't matter - assert_snapshot!( - infer(r#" -trait Trait1 { - fn method(&self) -> u32; -} -struct S1; -impl Trait1 for S1 {} -trait Trait2 { - fn method(&self) -> i128; -} -struct S2; -impl Trait2 for S2 {} -fn test() { - S1.method(); // -> u32 - S2.method(); // -> i128 -} -"#), - @r###" - [31; 35) 'self': &Self - [110; 114) 'self': &Self - [170; 228) '{ ...i128 }': () - [176; 178) 'S1': S1 - [176; 187) 'S1.method()': u32 - [203; 205) 'S2': S2 - [203; 214) 'S2.method()': i128 - "### - ); -} - -#[test] -fn infer_trait_method_scoped() { - // the trait implementation is intentionally incomplete -- it shouldn't matter - assert_snapshot!( - infer(r#" -struct S; -mod foo { - pub trait Trait1 { - fn method(&self) -> u32; - } - impl Trait1 for super::S {} -} -mod bar { - pub trait Trait2 { - fn method(&self) -> i128; - } - impl Trait2 for super::S {} -} - -mod foo_test { - use super::S; - use super::foo::Trait1; - fn test() { - S.method(); // -> u32 - } -} - -mod bar_test { - use super::S; - use super::bar::Trait2; - fn test() { - S.method(); // -> i128 - } -} -"#), - @r###" - [63; 67) 'self': &Self - [169; 173) 'self': &Self - [300; 337) '{ ... }': () - [310; 311) 'S': S - [310; 320) 'S.method()': u32 - [416; 454) '{ ... }': () - [426; 427) 'S': S - [426; 436) 'S.method()': i128 - "### - ); -} - -#[test] -fn infer_trait_method_generic_1() { - // the trait implementation is intentionally incomplete -- it shouldn't matter - assert_snapshot!( - infer(r#" -trait Trait { - fn method(&self) -> T; -} -struct S; -impl Trait for S {} -fn test() { - S.method(); -} -"#), - @r###" - [33; 37) 'self': &Self - [92; 111) '{ ...d(); }': () - [98; 99) 'S': S - [98; 108) 'S.method()': u32 - "### - ); -} - -#[test] -fn infer_trait_method_generic_more_params() { - // the trait implementation is intentionally incomplete -- it shouldn't matter - assert_snapshot!( - infer(r#" -trait Trait { - fn method1(&self) -> (T1, T2, T3); - fn method2(&self) -> (T3, T2, T1); -} -struct S1; -impl Trait for S1 {} -struct S2; -impl Trait for S2 {} -fn test() { - S1.method1(); // u8, u16, u32 - S1.method2(); // u32, u16, u8 - S2.method1(); // i8, i16, {unknown} - S2.method2(); // {unknown}, i16, i8 -} -"#), - @r###" - [43; 47) 'self': &Self - [82; 86) 'self': &Self - [210; 361) '{ ..., i8 }': () - [216; 218) 'S1': S1 - [216; 228) 'S1.method1()': (u8, u16, u32) - [250; 252) 'S1': S1 - [250; 262) 'S1.method2()': (u32, u16, u8) - [284; 286) 'S2': S2 - [284; 296) 'S2.method1()': (i8, i16, {unknown}) - [324; 326) 'S2': S2 - [324; 336) 'S2.method2()': ({unknown}, i16, i8) - "### - ); -} - -#[test] -fn infer_trait_method_generic_2() { - // the trait implementation is intentionally incomplete -- it shouldn't matter - assert_snapshot!( - infer(r#" -trait Trait { - fn method(&self) -> T; -} -struct S(T); -impl Trait for S {} -fn test() { - S(1u32).method(); -} -"#), - @r###" - [33; 37) 'self': &Self - [102; 127) '{ ...d(); }': () - [108; 109) 'S': S(T) -> S - [108; 115) 'S(1u32)': S - [108; 124) 'S(1u32...thod()': u32 - [110; 114) '1u32': u32 - "### - ); -} - -#[test] -fn infer_trait_assoc_method() { - assert_snapshot!( - infer(r#" -trait Default { - fn default() -> Self; -} -struct S; -impl Default for S {} -fn test() { - let s1: S = Default::default(); - let s2 = S::default(); - let s3 = ::default(); -} -"#), - @r###" - [87; 193) '{ ...t(); }': () - [97; 99) 's1': S - [105; 121) 'Defaul...efault': fn default() -> Self - [105; 123) 'Defaul...ault()': S - [133; 135) 's2': S - [138; 148) 'S::default': fn default() -> Self - [138; 150) 'S::default()': S - [160; 162) 's3': S - [165; 188) '() -> Self - [165; 190) ' { - fn make() -> T; -} -struct S; -impl Trait for S {} -struct G; -impl Trait for G {} -fn test() { - let a = S::make(); - let b = G::::make(); - let c: f64 = G::make(); -} -"#), - @r###" - [127; 211) '{ ...e(); }': () - [137; 138) 'a': u32 - [141; 148) 'S::make': fn make() -> T - [141; 150) 'S::make()': u32 - [160; 161) 'b': u64 - [164; 178) 'G::::make': fn make, u64>() -> T - [164; 180) 'G::, f64>() -> T - [199; 208) 'G::make()': f64 - "### - ); -} - -#[test] -fn infer_trait_assoc_method_generics_2() { - assert_snapshot!( - infer(r#" -trait Trait { - fn make() -> (T, U); -} -struct S; -impl Trait for S {} -struct G; -impl Trait for G {} -fn test() { - let a = S::make::(); - let b: (_, i64) = S::make(); - let c = G::::make::(); - let d: (u32, _) = G::make::(); - let e: (u32, i64) = G::make(); -} -"#), - @r###" - [135; 313) '{ ...e(); }': () - [145; 146) 'a': (u32, i64) - [149; 163) 'S::make::': fn make() -> (T, U) - [149; 165) 'S::mak...i64>()': (u32, i64) - [175; 176) 'b': (u32, i64) - [189; 196) 'S::make': fn make() -> (T, U) - [189; 198) 'S::make()': (u32, i64) - [208; 209) 'c': (u32, i64) - [212; 233) 'G::': fn make, u32, i64>() -> (T, U) - [212; 235) 'G::()': (u32, i64) - [245; 246) 'd': (u32, i64) - [259; 273) 'G::make::': fn make, u32, i64>() -> (T, U) - [259; 275) 'G::mak...i64>()': (u32, i64) - [285; 286) 'e': (u32, i64) - [301; 308) 'G::make': fn make, u32, i64>() -> (T, U) - [301; 310) 'G::make()': (u32, i64) - "### - ); -} - -#[test] -fn infer_trait_assoc_method_generics_3() { - assert_snapshot!( - infer(r#" -trait Trait { - fn make() -> (Self, T); -} -struct S; -impl Trait for S {} -fn test() { - let a = S::make(); -} -"#), - @r###" - [101; 127) '{ ...e(); }': () - [111; 112) 'a': (S, i64) - [115; 122) 'S::make': fn make, i64>() -> (Self, T) - [115; 124) 'S::make()': (S, i64) - "### - ); -} - -#[test] -fn infer_trait_assoc_method_generics_4() { - assert_snapshot!( - infer(r#" -trait Trait { - fn make() -> (Self, T); -} -struct S; -impl Trait for S {} -impl Trait for S {} -fn test() { - let a: (S, _) = S::make(); - let b: (_, i32) = S::make(); -} -"#), - @r###" - [131; 203) '{ ...e(); }': () - [141; 142) 'a': (S, i64) - [158; 165) 'S::make': fn make, i64>() -> (Self, T) - [158; 167) 'S::make()': (S, i64) - [177; 178) 'b': (S, i32) - [191; 198) 'S::make': fn make, i32>() -> (Self, T) - [191; 200) 'S::make()': (S, i32) - "### - ); -} - -#[test] -fn infer_trait_assoc_method_generics_5() { - assert_snapshot!( - infer(r#" -trait Trait { - fn make() -> (Self, T, U); -} -struct S; -impl Trait for S {} -fn test() { - let a = >::make::(); - let b: (S, _, _) = Trait::::make::(); -} -"#), - @r###" - [107; 211) '{ ...>(); }': () - [117; 118) 'a': (S, i64, u8) - [121; 150) '': fn make, i64, u8>() -> (Self, T, U) - [121; 152) '()': (S, i64, u8) - [162; 163) 'b': (S, i64, u8) - [182; 206) 'Trait:...::': fn make, i64, u8>() -> (Self, T, U) - [182; 208) 'Trait:...()': (S, i64, u8) - "### - ); -} - -#[test] -fn infer_from_bound_1() { - assert_snapshot!( - infer(r#" -trait Trait {} -struct S(T); -impl Trait for S {} -fn foo>(t: T) {} -fn test() { - let s = S(unknown); - foo(s); -} -"#), - @r###" - [86; 87) 't': T - [92; 94) '{}': () - [105; 144) '{ ...(s); }': () - [115; 116) 's': S - [119; 120) 'S': S(T) -> S - [119; 129) 'S(unknown)': S - [121; 128) 'unknown': u32 - [135; 138) 'foo': fn foo>(T) -> () - [135; 141) 'foo(s)': () - [139; 140) 's': S - "### - ); -} - -#[test] -fn infer_from_bound_2() { - assert_snapshot!( - infer(r#" -trait Trait {} -struct S(T); -impl Trait for S {} -fn foo>(t: T) -> U {} -fn test() { - let s = S(unknown); - let x: u32 = foo(s); -} -"#), - @r###" - [87; 88) 't': T - [98; 100) '{}': () - [111; 163) '{ ...(s); }': () - [121; 122) 's': S - [125; 126) 'S': S(T) -> S - [125; 135) 'S(unknown)': S - [127; 134) 'unknown': u32 - [145; 146) 'x': u32 - [154; 157) 'foo': fn foo>(T) -> U - [154; 160) 'foo(s)': u32 - [158; 159) 's': S - "### - ); -} - -#[test] -fn infer_call_trait_method_on_generic_param_1() { - assert_snapshot!( - infer(r#" -trait Trait { - fn method(&self) -> u32; -} -fn test(t: T) { - t.method(); -} -"#), - @r###" - [30; 34) 'self': &Self - [64; 65) 't': T - [70; 89) '{ ...d(); }': () - [76; 77) 't': T - [76; 86) 't.method()': u32 - "### - ); -} - -#[test] -fn infer_call_trait_method_on_generic_param_2() { - assert_snapshot!( - infer(r#" -trait Trait { - fn method(&self) -> T; -} -fn test>(t: T) { - t.method(); -} -"#), - @r###" - [33; 37) 'self': &Self - [71; 72) 't': T - [77; 96) '{ ...d(); }': () - [83; 84) 't': T - [83; 93) 't.method()': [missing name] - "### - ); -} - -#[test] -fn infer_with_multiple_trait_impls() { - assert_snapshot!( - infer(r#" -trait Into { - fn into(self) -> T; -} -struct S; -impl Into for S {} -impl Into for S {} -fn test() { - let x: u32 = S.into(); - let y: u64 = S.into(); - let z = Into::::into(S); -} -"#), - @r###" - [29; 33) 'self': Self - [111; 202) '{ ...(S); }': () - [121; 122) 'x': u32 - [130; 131) 'S': S - [130; 138) 'S.into()': u32 - [148; 149) 'y': u64 - [157; 158) 'S': S - [157; 165) 'S.into()': u64 - [175; 176) 'z': u64 - [179; 196) 'Into::...::into': fn into(Self) -> T - [179; 199) 'Into::...nto(S)': u64 - [197; 198) 'S': S - "### - ); -} - -#[test] -fn infer_project_associated_type() { - // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234 - assert_snapshot!( - infer(r#" -trait Iterable { - type Item; -} -struct S; -impl Iterable for S { type Item = u32; } -fn test() { - let x: ::Item = 1; - let y: ::Item = no_matter; - let z: T::Item = no_matter; - let a: ::Item = no_matter; -} -"#), - @r###" - [108; 261) '{ ...ter; }': () - [118; 119) 'x': u32 - [145; 146) '1': u32 - [156; 157) 'y': {unknown} - [183; 192) 'no_matter': {unknown} - [202; 203) 'z': {unknown} - [215; 224) 'no_matter': {unknown} - [234; 235) 'a': {unknown} - [249; 258) 'no_matter': {unknown} - "### - ); -} - -#[test] -fn infer_return_associated_type() { - assert_snapshot!( - infer(r#" -trait Iterable { - type Item; -} -struct S; -impl Iterable for S { type Item = u32; } -fn foo1(t: T) -> T::Item {} -fn foo2(t: T) -> ::Item {} -fn foo3(t: T) -> ::Item {} -fn test() { - let x = foo1(S); - let y = foo2(S); - let z = foo3(S); -} -"#), - @r###" - [106; 107) 't': T - [123; 125) '{}': () - [147; 148) 't': T - [178; 180) '{}': () - [202; 203) 't': T - [221; 223) '{}': () - [234; 300) '{ ...(S); }': () - [244; 245) 'x': u32 - [248; 252) 'foo1': fn foo1(T) -> ::Item - [248; 255) 'foo1(S)': u32 - [253; 254) 'S': S - [265; 266) 'y': u32 - [269; 273) 'foo2': fn foo2(T) -> ::Item - [269; 276) 'foo2(S)': u32 - [274; 275) 'S': S - [286; 287) 'z': u32 - [290; 294) 'foo3': fn foo3(T) -> ::Item - [290; 297) 'foo3(S)': u32 - [295; 296) 'S': S - "### - ); -} - -#[test] -fn infer_associated_type_bound() { - assert_snapshot!( - infer(r#" -trait Iterable { - type Item; -} -fn test>() { - let y: T::Item = unknown; -} -"#), - @r###" - [67; 100) '{ ...own; }': () - [77; 78) 'y': {unknown} - [90; 97) 'unknown': {unknown} - "### - ); -} - -#[test] -fn infer_const_body() { - assert_snapshot!( - infer(r#" -const A: u32 = 1 + 1; -static B: u64 = { let x = 1; x }; -"#), - @r###" - [16; 17) '1': u32 - [16; 21) '1 + 1': u32 - [20; 21) '1': u32 - [39; 55) '{ let ...1; x }': u64 - [45; 46) 'x': u64 - [49; 50) '1': u64 - [52; 53) 'x': u64 - "### - ); -} - -#[test] -fn tuple_struct_fields() { - assert_snapshot!( - infer(r#" -struct S(i32, u64); -fn test() -> u64 { - let a = S(4, 6); - let b = a.0; - a.1 -} -"#), - @r###" - [38; 87) '{ ... a.1 }': u64 - [48; 49) 'a': S - [52; 53) 'S': S(i32, u64) -> S - [52; 59) 'S(4, 6)': S - [54; 55) '4': i32 - [57; 58) '6': u64 - [69; 70) 'b': i32 - [73; 74) 'a': S - [73; 76) 'a.0': i32 - [82; 83) 'a': S - [82; 85) 'a.1': u64 - "### - ); -} - -#[test] -fn tuple_struct_with_fn() { - assert_snapshot!( - infer(r#" -struct S(fn(u32) -> u64); -fn test() -> u64 { - let a = S(|i| 2*i); - let b = a.0(4); - a.0(2) -} -"#), - @r###" - [44; 102) '{ ...0(2) }': u64 - [54; 55) 'a': S - [58; 59) 'S': S(fn(u32) -> u64) -> S - [58; 68) 'S(|i| 2*i)': S - [60; 67) '|i| 2*i': |i32| -> i32 - [61; 62) 'i': i32 - [64; 65) '2': i32 - [64; 67) '2*i': i32 - [66; 67) 'i': i32 - [78; 79) 'b': u64 - [82; 83) 'a': S - [82; 85) 'a.0': fn(u32) -> u64 - [82; 88) 'a.0(4)': u64 - [86; 87) '4': u32 - [94; 95) 'a': S - [94; 97) 'a.0': fn(u32) -> u64 - [94; 100) 'a.0(2)': u64 - [98; 99) '2': u32 - "### - ); -} - -#[test] -fn indexing_arrays() { - assert_snapshot!( - infer("fn main() { &mut [9][2]; }"), - @r###" - [10; 26) '{ &mut...[2]; }': () - [12; 23) '&mut [9][2]': &mut {unknown} - [17; 20) '[9]': [i32;_] - [17; 23) '[9][2]': {unknown} - [18; 19) '9': i32 - [21; 22) '2': i32 - "### - ) -} - -#[test] -fn infer_macros_expanded() { - assert_snapshot!( - infer(r#" -struct Foo(Vec); - -macro_rules! foo { - ($($item:expr),*) => { - { - Foo(vec![$($item,)*]) - } - }; -} - -fn main() { - let x = foo!(1,2); -} -"#), - @r###" - ![0; 17) '{Foo(v...,2,])}': Foo - ![1; 4) 'Foo': Foo({unknown}) -> Foo - ![1; 16) 'Foo(vec![1,2,])': Foo - ![5; 15) 'vec![1,2,]': {unknown} - [156; 182) '{ ...,2); }': () - [166; 167) 'x': Foo - "### - ); -} - -#[test] -fn infer_legacy_textual_scoped_macros_expanded() { - assert_snapshot!( - infer(r#" -struct Foo(Vec); - -#[macro_use] -mod m { - macro_rules! foo { - ($($item:expr),*) => { - { - Foo(vec![$($item,)*]) - } - }; - } -} - -fn main() { - let x = foo!(1,2); - let y = crate::foo!(1,2); -} -"#), - @r###" - ![0; 17) '{Foo(v...,2,])}': Foo - ![1; 4) 'Foo': Foo({unknown}) -> Foo - ![1; 16) 'Foo(vec![1,2,])': Foo - ![5; 15) 'vec![1,2,]': {unknown} - [195; 251) '{ ...,2); }': () - [205; 206) 'x': Foo - [228; 229) 'y': {unknown} - [232; 248) 'crate:...!(1,2)': {unknown} - "### - ); -} - -#[test] -fn infer_path_qualified_macros_expanded() { - assert_snapshot!( - infer(r#" -#[macro_export] -macro_rules! foo { - () => { 42i32 } -} - -mod m { - pub use super::foo as bar; -} - -fn main() { - let x = crate::foo!(); - let y = m::bar!(); -} -"#), - @r###" - ![0; 5) '42i32': i32 - ![0; 5) '42i32': i32 - [111; 164) '{ ...!(); }': () - [121; 122) 'x': i32 - [148; 149) 'y': i32 - "### - ); -} - -#[test] -fn infer_type_value_macro_having_same_name() { - assert_snapshot!( - infer(r#" -#[macro_export] -macro_rules! foo { - () => { - mod foo { - pub use super::foo; - } - }; - ($x:tt) => { - $x - }; -} - -foo!(); - -fn foo() { - let foo = foo::foo!(42i32); -} -"#), - @r###" - ![0; 5) '42i32': i32 - [171; 206) '{ ...32); }': () - [181; 184) 'foo': i32 - "### - ); -} - -#[test] -fn processes_impls_generated_by_macros() { - let t = type_at( - r#" -//- /main.rs -macro_rules! m { - ($ident:ident) => (impl Trait for $ident {}) -} -trait Trait { fn foo(self) -> u128 {} } -struct S; -m!(S); -fn test() { S.foo()<|>; } -"#, - ); - assert_eq!(t, "u128"); -} - -#[test] -fn infer_macro_with_dollar_crate_is_correct_in_expr() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs crate:main deps:foo -fn test() { - let x = (foo::foo!(1), foo::foo!(2)); - x<|>; -} - -//- /lib.rs crate:foo -#[macro_export] -macro_rules! foo { - (1) => { $crate::bar!() }; - (2) => { 1 + $crate::baz() }; -} - -#[macro_export] -macro_rules! bar { - () => { 42 } -} - -pub fn baz() -> usize { 31usize } -"#, - ); - assert_eq!("(i32, usize)", type_at_pos(&db, pos)); -} - -#[test] -fn method_resolution_unify_impl_self_type() { - let t = type_at( - r#" -//- /main.rs -struct S; -impl S { fn foo(&self) -> u8 {} } -impl S { fn foo(&self) -> i8 {} } -fn test() { (S::.foo(), S::.foo())<|>; } -"#, - ); - assert_eq!(t, "(u8, i8)"); -} - -#[test] -fn method_resolution_trait_before_autoref() { - let t = type_at( - r#" -//- /main.rs -trait Trait { fn foo(self) -> u128; } -struct S; -impl S { fn foo(&self) -> i8 { 0 } } -impl Trait for S { fn foo(self) -> u128 { 0 } } -fn test() { S.foo()<|>; } -"#, - ); - assert_eq!(t, "u128"); -} - -#[test] -fn method_resolution_by_value_before_autoref() { - let t = type_at( - r#" -//- /main.rs -trait Clone { fn clone(&self) -> Self; } -struct S; -impl Clone for S {} -impl Clone for &S {} -fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; } -"#, - ); - assert_eq!(t, "(S, S, &S)"); -} - -#[test] -fn method_resolution_trait_before_autoderef() { - let t = type_at( - r#" -//- /main.rs -trait Trait { fn foo(self) -> u128; } -struct S; -impl S { fn foo(self) -> i8 { 0 } } -impl Trait for &S { fn foo(self) -> u128 { 0 } } -fn test() { (&S).foo()<|>; } -"#, - ); - assert_eq!(t, "u128"); -} - -#[test] -fn method_resolution_impl_before_trait() { - let t = type_at( - r#" -//- /main.rs -trait Trait { fn foo(self) -> u128; } -struct S; -impl S { fn foo(self) -> i8 { 0 } } -impl Trait for S { fn foo(self) -> u128 { 0 } } -fn test() { S.foo()<|>; } -"#, - ); - assert_eq!(t, "i8"); -} - -#[test] -fn method_resolution_impl_ref_before_trait() { - let t = type_at( - r#" -//- /main.rs -trait Trait { fn foo(self) -> u128; } -struct S; -impl S { fn foo(&self) -> i8 { 0 } } -impl Trait for &S { fn foo(self) -> u128 { 0 } } -fn test() { S.foo()<|>; } -"#, - ); - assert_eq!(t, "i8"); -} - -#[test] -fn method_resolution_trait_autoderef() { - let t = type_at( - r#" -//- /main.rs -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for S { fn foo(self) -> u128 { 0 } } -fn test() { (&S).foo()<|>; } -"#, - ); - assert_eq!(t, "u128"); -} - -#[test] -fn method_resolution_trait_from_prelude() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs crate:main deps:other_crate -struct S; -impl Clone for S {} - -fn test() { - S.clone()<|>; -} - -//- /lib.rs crate:other_crate -#[prelude_import] use foo::*; - -mod foo { - trait Clone { - fn clone(&self) -> Self; - } -} -"#, - ); - assert_eq!("S", type_at_pos(&db, pos)); -} - -#[test] -fn method_resolution_where_clause_for_unknown_trait() { - // The blanket impl shouldn't apply because we can't even resolve UnknownTrait - let t = type_at( - r#" -//- /main.rs -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for T where T: UnknownTrait {} -fn test() { (&S).foo()<|>; } -"#, - ); - assert_eq!(t, "{unknown}"); -} - -#[test] -fn method_resolution_where_clause_not_met() { - // The blanket impl shouldn't apply because we can't prove S: Clone - let t = type_at( - r#" -//- /main.rs -trait Clone {} -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for T where T: Clone {} -fn test() { (&S).foo()<|>; } -"#, - ); - // This is also to make sure that we don't resolve to the foo method just - // because that's the only method named foo we can find, which would make - // the below tests not work - assert_eq!(t, "{unknown}"); -} - -#[test] -fn method_resolution_where_clause_inline_not_met() { - // The blanket impl shouldn't apply because we can't prove S: Clone - let t = type_at( - r#" -//- /main.rs -trait Clone {} -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for T {} -fn test() { (&S).foo()<|>; } -"#, - ); - assert_eq!(t, "{unknown}"); -} - -#[test] -fn method_resolution_where_clause_1() { - let t = type_at( - r#" -//- /main.rs -trait Clone {} -trait Trait { fn foo(self) -> u128; } -struct S; -impl Clone for S {} -impl Trait for T where T: Clone {} -fn test() { S.foo()<|>; } -"#, - ); - assert_eq!(t, "u128"); -} - -#[test] -fn method_resolution_where_clause_2() { - let t = type_at( - r#" -//- /main.rs -trait Into { fn into(self) -> T; } -trait From { fn from(other: T) -> Self; } -struct S1; -struct S2; -impl From for S1 {} -impl Into for T where U: From {} -fn test() { S2.into()<|>; } -"#, - ); - assert_eq!(t, "{unknown}"); -} - -#[test] -fn method_resolution_where_clause_inline() { - let t = type_at( - r#" -//- /main.rs -trait Into { fn into(self) -> T; } -trait From { fn from(other: T) -> Self; } -struct S1; -struct S2; -impl From for S1 {} -impl> Into for T {} -fn test() { S2.into()<|>; } -"#, - ); - assert_eq!(t, "{unknown}"); -} - -#[test] -fn method_resolution_encountering_fn_type() { - type_at( - r#" -//- /main.rs -fn foo() {} -trait FnOnce { fn call(self); } -fn test() { foo.call()<|>; } -"#, - ); -} - -#[test] -fn method_resolution_slow() { - // this can get quite slow if we set the solver size limit too high - let t = type_at( - r#" -//- /main.rs -trait SendX {} - -struct S1; impl SendX for S1 {} -struct S2; impl SendX for S2 {} -struct U1; - -trait Trait { fn method(self); } - -struct X1 {} -impl SendX for X1 where A: SendX, B: SendX {} - -struct S {} - -trait FnX {} - -impl Trait for S where C: FnX, B: SendX {} - -fn test() { (S {}).method()<|>; } -"#, - ); - assert_eq!(t, "()"); -} - -#[test] -fn shadowing_primitive() { - let t = type_at( - r#" -//- /main.rs -struct i32; -struct Foo; - -impl i32 { fn foo(&self) -> Foo { Foo } } - -fn main() { - let x: i32 = i32; - x.foo()<|>; -}"#, - ); - assert_eq!(t, "Foo"); -} - -#[test] -fn not_shadowing_primitive_by_module() { - let t = type_at( - r#" -//- /str.rs -fn foo() {} - -//- /main.rs -mod str; -fn foo() -> &'static str { "" } - -fn main() { - foo()<|>; -}"#, - ); - assert_eq!(t, "&str"); -} - -#[test] -fn not_shadowing_module_by_primitive() { - let t = type_at( - r#" -//- /str.rs -fn foo() -> u32 {0} - -//- /main.rs -mod str; -fn foo() -> &'static str { "" } - -fn main() { - str::foo()<|>; -}"#, - ); - assert_eq!(t, "u32"); -} - -#[test] -fn deref_trait() { - let t = type_at( - r#" -//- /main.rs -#[lang = "deref"] -trait Deref { - type Target; - fn deref(&self) -> &Self::Target; -} - -struct Arc; -impl Deref for Arc { - type Target = T; -} - -struct S; -impl S { - fn foo(&self) -> u128 {} -} - -fn test(s: Arc) { - (*s, s.foo())<|>; -} -"#, - ); - assert_eq!(t, "(S, u128)"); -} - -#[test] -fn deref_trait_with_inference_var() { - let t = type_at( - r#" -//- /main.rs -#[lang = "deref"] -trait Deref { - type Target; - fn deref(&self) -> &Self::Target; -} - -struct Arc; -fn new_arc() -> Arc {} -impl Deref for Arc { - type Target = T; -} - -struct S; -fn foo(a: Arc) {} - -fn test() { - let a = new_arc(); - let b = (*a)<|>; - foo(a); -} -"#, - ); - assert_eq!(t, "S"); -} - -#[test] -fn deref_trait_infinite_recursion() { - let t = type_at( - r#" -//- /main.rs -#[lang = "deref"] -trait Deref { - type Target; - fn deref(&self) -> &Self::Target; -} - -struct S; - -impl Deref for S { - type Target = S; -} - -fn test(s: S) { - s.foo()<|>; -} -"#, - ); - assert_eq!(t, "{unknown}"); -} - -#[test] -fn deref_trait_with_question_mark_size() { - let t = type_at( - r#" -//- /main.rs -#[lang = "deref"] -trait Deref { - type Target; - fn deref(&self) -> &Self::Target; -} - -struct Arc; -impl Deref for Arc { - type Target = T; -} - -struct S; -impl S { - fn foo(&self) -> u128 {} -} - -fn test(s: Arc) { - (*s, s.foo())<|>; -} -"#, - ); - assert_eq!(t, "(S, u128)"); -} - -#[test] -fn obligation_from_function_clause() { - let t = type_at( - r#" -//- /main.rs -struct S; - -trait Trait {} -impl Trait for S {} - -fn foo, U>(t: T) -> U {} - -fn test(s: S) { - foo(s)<|>; -} -"#, - ); - assert_eq!(t, "u32"); -} - -#[test] -fn obligation_from_method_clause() { - let t = type_at( - r#" -//- /main.rs -struct S; - -trait Trait {} -impl Trait for S {} - -struct O; -impl O { - fn foo, U>(&self, t: T) -> U {} -} - -fn test() { - O.foo(S)<|>; -} -"#, - ); - assert_eq!(t, "isize"); -} - -#[test] -fn obligation_from_self_method_clause() { - let t = type_at( - r#" -//- /main.rs -struct S; - -trait Trait {} -impl Trait for S {} - -impl S { - fn foo(&self) -> U where Self: Trait {} -} - -fn test() { - S.foo()<|>; -} -"#, - ); - assert_eq!(t, "i64"); -} - -#[test] -fn obligation_from_impl_clause() { - let t = type_at( - r#" -//- /main.rs -struct S; - -trait Trait {} -impl Trait<&str> for S {} - -struct O; -impl> O { - fn foo(&self) -> U {} -} - -fn test(o: O) { - o.foo()<|>; -} -"#, - ); - assert_eq!(t, "&str"); -} - -#[test] -fn generic_param_env_1() { - let t = type_at( - r#" -//- /main.rs -trait Clone {} -trait Trait { fn foo(self) -> u128; } -struct S; -impl Clone for S {} -impl Trait for T where T: Clone {} -fn test(t: T) { t.foo()<|>; } -"#, - ); - assert_eq!(t, "u128"); -} - -#[test] -fn generic_param_env_1_not_met() { - let t = type_at( - r#" -//- /main.rs -trait Clone {} -trait Trait { fn foo(self) -> u128; } -struct S; -impl Clone for S {} -impl Trait for T where T: Clone {} -fn test(t: T) { t.foo()<|>; } -"#, - ); - assert_eq!(t, "{unknown}"); -} - -#[test] -fn generic_param_env_2() { - let t = type_at( - r#" -//- /main.rs -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for S {} -fn test(t: T) { t.foo()<|>; } -"#, - ); - assert_eq!(t, "u128"); -} - -#[test] -fn generic_param_env_2_not_met() { - let t = type_at( - r#" -//- /main.rs -trait Trait { fn foo(self) -> u128; } -struct S; -impl Trait for S {} -fn test(t: T) { t.foo()<|>; } -"#, - ); - assert_eq!(t, "{unknown}"); -} - -#[test] -fn generic_param_env_deref() { - let t = type_at( - r#" -//- /main.rs -#[lang = "deref"] -trait Deref { - type Target; -} -trait Trait {} -impl Deref for T where T: Trait { - type Target = i128; -} -fn test(t: T) { (*t)<|>; } -"#, - ); - assert_eq!(t, "i128"); -} - -#[test] -fn associated_type_placeholder() { - let t = type_at( - r#" -//- /main.rs -pub trait ApplyL { - type Out; -} - -pub struct RefMutL; - -impl ApplyL for RefMutL { - type Out = ::Out; -} - -fn test() { - let y: as ApplyL>::Out = no_matter; - y<|>; -} -"#, - ); - // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. - // FIXME: fix type parameter names going missing when going through Chalk - assert_eq!(t, "ApplyL::Out<[missing name]>"); -} - -#[test] -fn associated_type_placeholder_2() { - let t = type_at( - r#" -//- /main.rs -pub trait ApplyL { - type Out; -} -fn foo(t: T) -> ::Out; - -fn test(t: T) { - let y = foo(t); - y<|>; -} -"#, - ); - // FIXME here Chalk doesn't normalize the type to a placeholder. I think we - // need to add a rule like Normalize(::Out -> ApplyL::Out) - // to the trait env ourselves here; probably Chalk can't do this by itself. - // assert_eq!(t, "ApplyL::Out<[missing name]>"); - assert_eq!(t, "{unknown}"); -} - -#[test] -fn impl_trait() { - assert_snapshot!( - infer(r#" -trait Trait { - fn foo(&self) -> T; - fn foo2(&self) -> i64; -} -fn bar() -> impl Trait {} - -fn test(x: impl Trait, y: &impl Trait) { - x; - y; - let z = bar(); - x.foo(); - y.foo(); - z.foo(); - x.foo2(); - y.foo2(); - z.foo2(); -} -"#), - @r###" - [30; 34) 'self': &Self - [55; 59) 'self': &Self - [99; 101) '{}': () - [111; 112) 'x': impl Trait - [131; 132) 'y': &impl Trait - [152; 269) '{ ...2(); }': () - [158; 159) 'x': impl Trait - [165; 166) 'y': &impl Trait - [176; 177) 'z': impl Trait - [180; 183) 'bar': fn bar() -> impl Trait - [180; 185) 'bar()': impl Trait - [191; 192) 'x': impl Trait - [191; 198) 'x.foo()': u64 - [204; 205) 'y': &impl Trait - [204; 211) 'y.foo()': u64 - [217; 218) 'z': impl Trait - [217; 224) 'z.foo()': u64 - [230; 231) 'x': impl Trait - [230; 238) 'x.foo2()': i64 - [244; 245) 'y': &impl Trait - [244; 252) 'y.foo2()': i64 - [258; 259) 'z': impl Trait - [258; 266) 'z.foo2()': i64 - "### - ); -} - -#[test] -fn dyn_trait() { - assert_snapshot!( - infer(r#" -trait Trait { - fn foo(&self) -> T; - fn foo2(&self) -> i64; -} -fn bar() -> dyn Trait {} - -fn test(x: dyn Trait, y: &dyn Trait) { - x; - y; - let z = bar(); - x.foo(); - y.foo(); - z.foo(); - x.foo2(); - y.foo2(); - z.foo2(); -} -"#), - @r###" - [30; 34) 'self': &Self - [55; 59) 'self': &Self - [98; 100) '{}': () - [110; 111) 'x': dyn Trait - [129; 130) 'y': &dyn Trait - [149; 266) '{ ...2(); }': () - [155; 156) 'x': dyn Trait - [162; 163) 'y': &dyn Trait - [173; 174) 'z': dyn Trait - [177; 180) 'bar': fn bar() -> dyn Trait - [177; 182) 'bar()': dyn Trait - [188; 189) 'x': dyn Trait - [188; 195) 'x.foo()': u64 - [201; 202) 'y': &dyn Trait - [201; 208) 'y.foo()': u64 - [214; 215) 'z': dyn Trait - [214; 221) 'z.foo()': u64 - [227; 228) 'x': dyn Trait - [227; 235) 'x.foo2()': i64 - [241; 242) 'y': &dyn Trait - [241; 249) 'y.foo2()': i64 - [255; 256) 'z': dyn Trait - [255; 263) 'z.foo2()': i64 - "### - ); -} - -#[test] -fn dyn_trait_bare() { - assert_snapshot!( - infer(r#" -trait Trait { - fn foo(&self) -> u64; -} -fn bar() -> Trait {} - -fn test(x: Trait, y: &Trait) -> u64 { - x; - y; - let z = bar(); - x.foo(); - y.foo(); - z.foo(); -} -"#), - @r###" - [27; 31) 'self': &Self - [61; 63) '{}': () - [73; 74) 'x': dyn Trait - [83; 84) 'y': &dyn Trait - [101; 176) '{ ...o(); }': () - [107; 108) 'x': dyn Trait - [114; 115) 'y': &dyn Trait - [125; 126) 'z': dyn Trait - [129; 132) 'bar': fn bar() -> dyn Trait - [129; 134) 'bar()': dyn Trait - [140; 141) 'x': dyn Trait - [140; 147) 'x.foo()': u64 - [153; 154) 'y': &dyn Trait - [153; 160) 'y.foo()': u64 - [166; 167) 'z': dyn Trait - [166; 173) 'z.foo()': u64 - "### - ); -} - -#[test] -fn weird_bounds() { - assert_snapshot!( - infer(r#" -trait Trait {} -fn test() { - let a: impl Trait + 'lifetime = foo; - let b: impl 'lifetime = foo; - let b: impl (Trait) = foo; - let b: impl ('lifetime) = foo; - let d: impl ?Sized = foo; - let e: impl Trait + ?Sized = foo; -} -"#), - @r###" - [26; 237) '{ ...foo; }': () - [36; 37) 'a': impl Trait + {error} - [64; 67) 'foo': impl Trait + {error} - [77; 78) 'b': impl {error} - [97; 100) 'foo': impl {error} - [110; 111) 'b': impl Trait - [128; 131) 'foo': impl Trait - [141; 142) 'b': impl {error} - [163; 166) 'foo': impl {error} - [176; 177) 'd': impl {error} - [193; 196) 'foo': impl {error} - [206; 207) 'e': impl Trait + {error} - [231; 234) 'foo': impl Trait + {error} - "### - ); -} - -#[test] -fn assoc_type_bindings() { - assert_snapshot!( - infer(r#" -trait Trait { - type Type; -} - -fn get(t: T) -> ::Type {} -fn get2>(t: T) -> U {} -fn set>(t: T) -> T {t} - -struct S; -impl Trait for S { type Type = T; } - -fn test>(x: T, y: impl Trait) { - get(x); - get2(x); - get(y); - get2(y); - get(set(S)); - get2(set(S)); - get2(S::); -} -"#), - @r###" - [50; 51) 't': T - [78; 80) '{}': () - [112; 113) 't': T - [123; 125) '{}': () - [155; 156) 't': T - [166; 169) '{t}': T - [167; 168) 't': T - [257; 258) 'x': T - [263; 264) 'y': impl Trait - [290; 398) '{ ...r>); }': () - [296; 299) 'get': fn get(T) -> ::Type - [296; 302) 'get(x)': {unknown} - [300; 301) 'x': T - [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U - [308; 315) 'get2(x)': {unknown} - [313; 314) 'x': T - [321; 324) 'get': fn get>(T) -> ::Type - [321; 327) 'get(y)': {unknown} - [325; 326) 'y': impl Trait - [333; 337) 'get2': fn get2<{unknown}, impl Trait>(T) -> U - [333; 340) 'get2(y)': {unknown} - [338; 339) 'y': impl Trait - [346; 349) 'get': fn get>(T) -> ::Type - [346; 357) 'get(set(S))': u64 - [350; 353) 'set': fn set>(T) -> T - [350; 356) 'set(S)': S - [354; 355) 'S': S - [363; 367) 'get2': fn get2>(T) -> U - [363; 375) 'get2(set(S))': u64 - [368; 371) 'set': fn set>(T) -> T - [368; 374) 'set(S)': S - [372; 373) 'S': S - [381; 385) 'get2': fn get2>(T) -> U - [381; 395) 'get2(S::)': str - [386; 394) 'S::': S - "### - ); -} - -#[test] -fn impl_trait_assoc_binding_projection_bug() { - let (db, pos) = TestDB::with_position( - r#" -//- /main.rs crate:main deps:std -pub trait Language { - type Kind; -} -pub enum RustLanguage {} -impl Language for RustLanguage { - type Kind = SyntaxKind; -} -struct SyntaxNode {} -fn foo() -> impl Iterator> {} - -trait Clone { - fn clone(&self) -> Self; -} - -fn api_walkthrough() { - for node in foo() { - node.clone()<|>; - } -} - -//- /std.rs crate:std -#[prelude_import] use iter::*; -mod iter { - trait IntoIterator { - type Item; - } - trait Iterator { - type Item; - } - impl IntoIterator for T { - type Item = ::Item; - } -} -"#, - ); - assert_eq!("{unknown}", type_at_pos(&db, pos)); -} - -#[test] -fn projection_eq_within_chalk() { - // std::env::set_var("CHALK_DEBUG", "1"); - assert_snapshot!( - infer(r#" -trait Trait1 { - type Type; -} -trait Trait2 { - fn foo(self) -> T; -} -impl Trait2 for U where U: Trait1 {} - -fn test>(x: T) { - x.foo(); -} -"#), - @r###" - [62; 66) 'self': Self - [164; 165) 'x': T - [170; 186) '{ ...o(); }': () - [176; 177) 'x': T - [176; 183) 'x.foo()': {unknown} - "### - ); -} - -#[test] -fn where_clause_trait_in_scope_for_method_resolution() { - let t = type_at( - r#" -//- /main.rs -mod foo { - trait Trait { - fn foo(&self) -> u32 {} - } -} - -fn test(x: T) { - x.foo()<|>; -} -"#, - ); - assert_eq!(t, "u32"); -} - -#[test] -fn super_trait_method_resolution() { - assert_snapshot!( - infer(r#" -mod foo { - trait SuperTrait { - fn foo(&self) -> u32 {} - } -} -trait Trait1: foo::SuperTrait {} -trait Trait2 where Self: foo::SuperTrait {} - -fn test(x: T, y: U) { - x.foo(); - y.foo(); -} -"#), - @r###" - [50; 54) 'self': &Self - [63; 65) '{}': () - [182; 183) 'x': T - [188; 189) 'y': U - [194; 223) '{ ...o(); }': () - [200; 201) 'x': T - [200; 207) 'x.foo()': u32 - [213; 214) 'y': U - [213; 220) 'y.foo()': u32 - "### - ); -} - -#[test] -fn super_trait_cycle() { - // This just needs to not crash - assert_snapshot!( - infer(r#" -trait A: B {} -trait B: A {} - -fn test(x: T) { - x.foo(); -} -"#), - @r###" - [44; 45) 'x': T - [50; 66) '{ ...o(); }': () - [56; 57) 'x': T - [56; 63) 'x.foo()': {unknown} - "### - ); -} - -#[test] -fn super_trait_assoc_type_bounds() { - assert_snapshot!( - infer(r#" -trait SuperTrait { type Type; } -trait Trait where Self: SuperTrait {} - -fn get2>(t: T) -> U {} -fn set>(t: T) -> T {t} - -struct S; -impl SuperTrait for S { type Type = T; } -impl Trait for S {} - -fn test() { - get2(set(S)); -} -"#), - @r###" - [103; 104) 't': T - [114; 116) '{}': () - [146; 147) 't': T - [157; 160) '{t}': T - [158; 159) 't': T - [259; 280) '{ ...S)); }': () - [265; 269) 'get2': fn get2>(T) -> U - [265; 277) 'get2(set(S))': u64 - [270; 273) 'set': fn set>(T) -> T - [270; 276) 'set(S)': S - [274; 275) 'S': S - "### - ); -} - -#[test] -fn fn_trait() { - assert_snapshot!( - infer(r#" -trait FnOnce { - type Output; - - fn call_once(self, args: Args) -> >::Output; -} - -fn test u128>(f: F) { - f.call_once((1, 2)); -} -"#), - @r###" - [57; 61) 'self': Self - [63; 67) 'args': Args - [150; 151) 'f': F - [156; 184) '{ ...2)); }': () - [162; 163) 'f': F - [162; 181) 'f.call...1, 2))': {unknown} - [174; 180) '(1, 2)': (u32, u64) - [175; 176) '1': u32 - [178; 179) '2': u64 - "### - ); -} - -#[test] -fn closure_1() { - assert_snapshot!( - infer(r#" -#[lang = "fn_once"] -trait FnOnce { - type Output; -} - -enum Option { Some(T), None } -impl Option { - fn map U>(self, f: F) -> Option {} -} - -fn test() { - let x = Option::Some(1u32); - x.map(|v| v + 1); - x.map(|_v| 1u64); - let y: Option = x.map(|_v| 1); -} -"#), - @r###" - [148; 152) 'self': Option - [154; 155) 'f': F - [173; 175) '{}': () - [189; 308) '{ ... 1); }': () - [199; 200) 'x': Option - [203; 215) 'Option::Some': Some(T) -> Option - [203; 221) 'Option...(1u32)': Option - [216; 220) '1u32': u32 - [227; 228) 'x': Option - [227; 243) 'x.map(...v + 1)': Option - [233; 242) '|v| v + 1': |u32| -> u32 - [234; 235) 'v': u32 - [237; 238) 'v': u32 - [237; 242) 'v + 1': u32 - [241; 242) '1': u32 - [249; 250) 'x': Option - [249; 265) 'x.map(... 1u64)': Option - [255; 264) '|_v| 1u64': |u32| -> u64 - [256; 258) '_v': u32 - [260; 264) '1u64': u64 - [275; 276) 'y': Option - [292; 293) 'x': Option - [292; 305) 'x.map(|_v| 1)': Option - [298; 304) '|_v| 1': |u32| -> i64 - [299; 301) '_v': u32 - [303; 304) '1': i64 - "### - ); -} - -#[test] -fn closure_2() { - assert_snapshot!( - infer(r#" -trait FnOnce { - type Output; -} - -fn test u64>(f: F) { - f(1); - let g = |v| v + 1; - g(1u64); - let h = |v| 1u128 + v; -} -"#), - @r###" - [73; 74) 'f': F - [79; 155) '{ ...+ v; }': () - [85; 86) 'f': F - [85; 89) 'f(1)': {unknown} - [87; 88) '1': i32 - [99; 100) 'g': |u64| -> i32 - [103; 112) '|v| v + 1': |u64| -> i32 - [104; 105) 'v': u64 - [107; 108) 'v': u64 - [107; 112) 'v + 1': i32 - [111; 112) '1': i32 - [118; 119) 'g': |u64| -> i32 - [118; 125) 'g(1u64)': i32 - [120; 124) '1u64': u64 - [135; 136) 'h': |u128| -> u128 - [139; 152) '|v| 1u128 + v': |u128| -> u128 - [140; 141) 'v': u128 - [143; 148) '1u128': u128 - [143; 152) '1u128 + v': u128 - [151; 152) 'v': u128 - "### - ); -} - -#[test] -fn closure_as_argument_inference_order() { - assert_snapshot!( - infer(r#" -#[lang = "fn_once"] -trait FnOnce { - type Output; -} - -fn foo1 U>(x: T, f: F) -> U {} -fn foo2 U>(f: F, x: T) -> U {} - -struct S; -impl S { - fn method(self) -> u64; - - fn foo1 U>(self, x: T, f: F) -> U {} - fn foo2 U>(self, f: F, x: T) -> U {} -} - -fn test() { - let x1 = foo1(S, |s| s.method()); - let x2 = foo2(|s| s.method(), S); - let x3 = S.foo1(S, |s| s.method()); - let x4 = S.foo2(|s| s.method(), S); -} -"#), - @r###" - [95; 96) 'x': T - [101; 102) 'f': F - [112; 114) '{}': () - [148; 149) 'f': F - [154; 155) 'x': T - [165; 167) '{}': () - [202; 206) 'self': S - [254; 258) 'self': S - [260; 261) 'x': T - [266; 267) 'f': F - [277; 279) '{}': () - [317; 321) 'self': S - [323; 324) 'f': F - [329; 330) 'x': T - [340; 342) '{}': () - [356; 515) '{ ... S); }': () - [366; 368) 'x1': u64 - [371; 375) 'foo1': fn foo1 u64>(T, F) -> U - [371; 394) 'foo1(S...hod())': u64 - [376; 377) 'S': S - [379; 393) '|s| s.method()': |S| -> u64 - [380; 381) 's': S - [383; 384) 's': S - [383; 393) 's.method()': u64 - [404; 406) 'x2': u64 - [409; 413) 'foo2': fn foo2 u64>(F, T) -> U - [409; 432) 'foo2(|...(), S)': u64 - [414; 428) '|s| s.method()': |S| -> u64 - [415; 416) 's': S - [418; 419) 's': S - [418; 428) 's.method()': u64 - [430; 431) 'S': S - [442; 444) 'x3': u64 - [447; 448) 'S': S - [447; 472) 'S.foo1...hod())': u64 - [454; 455) 'S': S - [457; 471) '|s| s.method()': |S| -> u64 - [458; 459) 's': S - [461; 462) 's': S - [461; 471) 's.method()': u64 - [482; 484) 'x4': u64 - [487; 488) 'S': S - [487; 512) 'S.foo2...(), S)': u64 - [494; 508) '|s| s.method()': |S| -> u64 - [495; 496) 's': S - [498; 499) 's': S - [498; 508) 's.method()': u64 - [510; 511) 'S': S - "### - ); -} - -#[test] -fn unselected_projection_in_trait_env_1() { - let t = type_at( - r#" -//- /main.rs -trait Trait { - type Item; -} - -trait Trait2 { - fn foo(&self) -> u32; -} - -fn test() where T::Item: Trait2 { - let x: T::Item = no_matter; - x.foo()<|>; -} -"#, - ); - assert_eq!(t, "u32"); -} - -#[test] -fn unselected_projection_in_trait_env_2() { - let t = type_at( - r#" -//- /main.rs -trait Trait { - type Item; -} - -trait Trait2 { - fn foo(&self) -> u32; -} - -fn test() where T::Item: Trait2, T: Trait, U: Trait<()> { - let x: T::Item = no_matter; - x.foo()<|>; -} -"#, - ); - assert_eq!(t, "u32"); -} - -#[test] -fn trait_impl_self_ty() { - let t = type_at( - r#" -//- /main.rs -trait Trait { - fn foo(&self); -} - -struct S; - -impl Trait for S {} - -fn test() { - S.foo()<|>; -} -"#, - ); - assert_eq!(t, "()"); -} - -#[test] -fn trait_impl_self_ty_cycle() { - let t = type_at( - r#" -//- /main.rs -trait Trait { - fn foo(&self); -} - -struct S; - -impl Trait for S {} - -fn test() { - S.foo()<|>; -} -"#, - ); - assert_eq!(t, "{unknown}"); -} - -#[test] -fn unselected_projection_in_trait_env_cycle_1() { - let t = type_at( - r#" -//- /main.rs -trait Trait { - type Item; -} - -trait Trait2 {} - -fn test() where T: Trait2 { - let x: T::Item = no_matter<|>; -} -"#, - ); - // this is a legitimate cycle - assert_eq!(t, "{unknown}"); -} - -#[test] -fn unselected_projection_in_trait_env_cycle_2() { - let t = type_at( - r#" -//- /main.rs -trait Trait { - type Item; -} - -fn test() where T: Trait, U: Trait { - let x: T::Item = no_matter<|>; -} -"#, - ); - // this is a legitimate cycle - assert_eq!(t, "{unknown}"); -} - -#[test] -fn bug_2467() { - assert_snapshot!( - infer(r#" -struct S(T); -impl S { - fn foo(self) -> T; -} -fn test() { - // needs to nest multiple times for variable indices to get high enough - let a = S::foo(S(1)); - let b = S::foo(S(a)); - let c = S::foo(S(b)); - let d: u32 = S::foo(S(c)); -} -"#), - @r###" - [43; 47) 'self': S - [67; 255) '{ ...c)); }': () - [153; 154) 'a': u32 - [157; 163) 'S::foo': fn foo(S) -> T - [157; 169) 'S::foo(S(1))': u32 - [164; 165) 'S': S(T) -> S - [164; 168) 'S(1)': S - [166; 167) '1': u32 - [179; 180) 'b': u32 - [183; 189) 'S::foo': fn foo(S) -> T - [183; 195) 'S::foo(S(a))': u32 - [190; 191) 'S': S(T) -> S - [190; 194) 'S(a)': S - [192; 193) 'a': u32 - [205; 206) 'c': u32 - [209; 215) 'S::foo': fn foo(S) -> T - [209; 221) 'S::foo(S(b))': u32 - [216; 217) 'S': S(T) -> S - [216; 220) 'S(b)': S - [218; 219) 'b': u32 - [231; 232) 'd': u32 - [240; 246) 'S::foo': fn foo(S) -> T - [240; 252) 'S::foo(S(c))': u32 - [247; 248) 'S': S(T) -> S - [247; 251) 'S(c)': S - [249; 250) 'c': u32 - "### - ); -} - fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { let file = db.parse(pos.file_id).ok().unwrap(); let expr = algo::find_node_at_offset::(file.syntax(), pos.offset).unwrap(); @@ -5095,60 +256,3 @@ fn no_such_field_diagnostics() { "### ); } - -#[test] -fn infer_builtin_macros_line() { - assert_snapshot!( - infer(r#" -#[rustc_builtin_macro] -macro_rules! line {() => {}} - -fn main() { - let x = line!(); -} -"#), - @r###" - ![0; 1) '6': i32 - [64; 88) '{ ...!(); }': () - [74; 75) 'x': i32 - "### - ); -} - -#[test] -fn infer_builtin_macros_file() { - assert_snapshot!( - infer(r#" -#[rustc_builtin_macro] -macro_rules! file {() => {}} - -fn main() { - let x = file!(); -} -"#), - @r###" - ![0; 2) '""': &str - [64; 88) '{ ...!(); }': () - [74; 75) 'x': &str - "### - ); -} - -#[test] -fn infer_builtin_macros_column() { - assert_snapshot!( - infer(r#" -#[rustc_builtin_macro] -macro_rules! column {() => {}} - -fn main() { - let x = column!(); -} -"#), - @r###" - ![0; 2) '13': i32 - [66; 92) '{ ...!(); }': () - [76; 77) 'x': i32 - "### - ); -} diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs new file mode 100644 index 000000000..0d9a35ce0 --- /dev/null +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -0,0 +1,268 @@ +use super::{infer, type_at, type_at_pos}; +use crate::test_db::TestDB; +use insta::assert_snapshot; +use ra_db::fixture::WithFixture; + +#[test] +fn cfg_impl_block() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:foo cfg:test +use foo::S as T; +struct S; + +#[cfg(test)] +impl S { + fn foo1(&self) -> i32 { 0 } +} + +#[cfg(not(test))] +impl S { + fn foo2(&self) -> i32 { 0 } +} + +fn test() { + let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4()); + t<|>; +} + +//- /foo.rs crate:foo +struct S; + +#[cfg(not(test))] +impl S { + fn foo3(&self) -> i32 { 0 } +} + +#[cfg(test)] +impl S { + fn foo4(&self) -> i32 { 0 } +} +"#, + ); + assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos)); +} + +#[test] +fn infer_macros_expanded() { + assert_snapshot!( + infer(r#" +struct Foo(Vec); + +macro_rules! foo { + ($($item:expr),*) => { + { + Foo(vec![$($item,)*]) + } + }; +} + +fn main() { + let x = foo!(1,2); +} +"#), + @r###" + ![0; 17) '{Foo(v...,2,])}': Foo + ![1; 4) 'Foo': Foo({unknown}) -> Foo + ![1; 16) 'Foo(vec![1,2,])': Foo + ![5; 15) 'vec![1,2,]': {unknown} + [156; 182) '{ ...,2); }': () + [166; 167) 'x': Foo + "### + ); +} + +#[test] +fn infer_legacy_textual_scoped_macros_expanded() { + assert_snapshot!( + infer(r#" +struct Foo(Vec); + +#[macro_use] +mod m { + macro_rules! foo { + ($($item:expr),*) => { + { + Foo(vec![$($item,)*]) + } + }; + } +} + +fn main() { + let x = foo!(1,2); + let y = crate::foo!(1,2); +} +"#), + @r###" + ![0; 17) '{Foo(v...,2,])}': Foo + ![1; 4) 'Foo': Foo({unknown}) -> Foo + ![1; 16) 'Foo(vec![1,2,])': Foo + ![5; 15) 'vec![1,2,]': {unknown} + [195; 251) '{ ...,2); }': () + [205; 206) 'x': Foo + [228; 229) 'y': {unknown} + [232; 248) 'crate:...!(1,2)': {unknown} + "### + ); +} + +#[test] +fn infer_path_qualified_macros_expanded() { + assert_snapshot!( + infer(r#" +#[macro_export] +macro_rules! foo { + () => { 42i32 } +} + +mod m { + pub use super::foo as bar; +} + +fn main() { + let x = crate::foo!(); + let y = m::bar!(); +} +"#), + @r###" + ![0; 5) '42i32': i32 + ![0; 5) '42i32': i32 + [111; 164) '{ ...!(); }': () + [121; 122) 'x': i32 + [148; 149) 'y': i32 + "### + ); +} + +#[test] +fn infer_type_value_macro_having_same_name() { + assert_snapshot!( + infer(r#" +#[macro_export] +macro_rules! foo { + () => { + mod foo { + pub use super::foo; + } + }; + ($x:tt) => { + $x + }; +} + +foo!(); + +fn foo() { + let foo = foo::foo!(42i32); +} +"#), + @r###" + ![0; 5) '42i32': i32 + [171; 206) '{ ...32); }': () + [181; 184) 'foo': i32 + "### + ); +} + +#[test] +fn processes_impls_generated_by_macros() { + let t = type_at( + r#" +//- /main.rs +macro_rules! m { + ($ident:ident) => (impl Trait for $ident {}) +} +trait Trait { fn foo(self) -> u128 {} } +struct S; +m!(S); +fn test() { S.foo()<|>; } +"#, + ); + assert_eq!(t, "u128"); +} + +#[test] +fn infer_macro_with_dollar_crate_is_correct_in_expr() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:foo +fn test() { + let x = (foo::foo!(1), foo::foo!(2)); + x<|>; +} + +//- /lib.rs crate:foo +#[macro_export] +macro_rules! foo { + (1) => { $crate::bar!() }; + (2) => { 1 + $crate::baz() }; +} + +#[macro_export] +macro_rules! bar { + () => { 42 } +} + +pub fn baz() -> usize { 31usize } +"#, + ); + assert_eq!("(i32, usize)", type_at_pos(&db, pos)); +} + +#[test] +fn infer_builtin_macros_line() { + assert_snapshot!( + infer(r#" +#[rustc_builtin_macro] +macro_rules! line {() => {}} + +fn main() { + let x = line!(); +} +"#), + @r###" + ![0; 1) '6': i32 + [64; 88) '{ ...!(); }': () + [74; 75) 'x': i32 + "### + ); +} + +#[test] +fn infer_builtin_macros_file() { + assert_snapshot!( + infer(r#" +#[rustc_builtin_macro] +macro_rules! file {() => {}} + +fn main() { + let x = file!(); +} +"#), + @r###" + ![0; 2) '""': &str + [64; 88) '{ ...!(); }': () + [74; 75) 'x': &str + "### + ); +} + +#[test] +fn infer_builtin_macros_column() { + assert_snapshot!( + infer(r#" +#[rustc_builtin_macro] +macro_rules! column {() => {}} + +fn main() { + let x = column!(); +} +"#), + @r###" + ![0; 2) '13': i32 + [66; 92) '{ ...!(); }': () + [76; 77) 'x': i32 + "### + ); +} diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs new file mode 100644 index 000000000..45164c9e9 --- /dev/null +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs @@ -0,0 +1,1005 @@ +use super::{infer, type_at, type_at_pos}; +use crate::test_db::TestDB; +use insta::assert_snapshot; +use ra_db::fixture::WithFixture; + +#[test] +fn infer_slice_method() { + assert_snapshot!( + infer(r#" +#[lang = "slice"] +impl [T] { + fn foo(&self) -> T { + loop {} + } +} + +#[lang = "slice_alloc"] +impl [T] {} + +fn test() { + <[_]>::foo(b"foo"); +} +"#), + @r###" + [45; 49) 'self': &[T] + [56; 79) '{ ... }': T + [66; 73) 'loop {}': ! + [71; 73) '{}': () + [133; 160) '{ ...o"); }': () + [139; 149) '<[_]>::foo': fn foo(&[T]) -> T + [139; 157) '<[_]>:..."foo")': u8 + [150; 156) 'b"foo"': &[u8] + "### + ); +} + +#[test] +fn infer_associated_method_struct() { + assert_snapshot!( + infer(r#" +struct A { x: u32 } + +impl A { + fn new() -> A { + A { x: 0 } + } +} +fn test() { + let a = A::new(); + a.x; +} +"#), + @r###" + [49; 75) '{ ... }': A + [59; 69) 'A { x: 0 }': A + [66; 67) '0': u32 + [88; 122) '{ ...a.x; }': () + [98; 99) 'a': A + [102; 108) 'A::new': fn new() -> A + [102; 110) 'A::new()': A + [116; 117) 'a': A + [116; 119) 'a.x': u32 + "### + ); +} + +#[test] +fn infer_associated_method_enum() { + assert_snapshot!( + infer(r#" +enum A { B, C } + +impl A { + pub fn b() -> A { + A::B + } + pub fn c() -> A { + A::C + } +} +fn test() { + let a = A::b(); + a; + let c = A::c(); + c; +} +"#), + @r###" + [47; 67) '{ ... }': A + [57; 61) 'A::B': A + [88; 108) '{ ... }': A + [98; 102) 'A::C': A + [121; 178) '{ ... c; }': () + [131; 132) 'a': A + [135; 139) 'A::b': fn b() -> A + [135; 141) 'A::b()': A + [147; 148) 'a': A + [158; 159) 'c': A + [162; 166) 'A::c': fn c() -> A + [162; 168) 'A::c()': A + [174; 175) 'c': A + "### + ); +} + +#[test] +fn infer_associated_method_with_modules() { + assert_snapshot!( + infer(r#" +mod a { + struct A; + impl A { pub fn thing() -> A { A {} }} +} + +mod b { + struct B; + impl B { pub fn thing() -> u32 { 99 }} + + mod c { + struct C; + impl C { pub fn thing() -> C { C {} }} + } +} +use b::c; + +fn test() { + let x = a::A::thing(); + let y = b::B::thing(); + let z = c::C::thing(); +} +"#), + @r###" + [56; 64) '{ A {} }': A + [58; 62) 'A {}': A + [126; 132) '{ 99 }': u32 + [128; 130) '99': u32 + [202; 210) '{ C {} }': C + [204; 208) 'C {}': C + [241; 325) '{ ...g(); }': () + [251; 252) 'x': A + [255; 266) 'a::A::thing': fn thing() -> A + [255; 268) 'a::A::thing()': A + [278; 279) 'y': u32 + [282; 293) 'b::B::thing': fn thing() -> u32 + [282; 295) 'b::B::thing()': u32 + [305; 306) 'z': C + [309; 320) 'c::C::thing': fn thing() -> C + [309; 322) 'c::C::thing()': C + "### + ); +} + +#[test] +fn infer_associated_method_generics() { + assert_snapshot!( + infer(r#" +struct Gen { + val: T +} + +impl Gen { + pub fn make(val: T) -> Gen { + Gen { val } + } +} + +fn test() { + let a = Gen::make(0u32); +} +"#), + @r###" + [64; 67) 'val': T + [82; 109) '{ ... }': Gen + [92; 103) 'Gen { val }': Gen + [98; 101) 'val': T + [123; 155) '{ ...32); }': () + [133; 134) 'a': Gen + [137; 146) 'Gen::make': fn make(T) -> Gen + [137; 152) 'Gen::make(0u32)': Gen + [147; 151) '0u32': u32 + "### + ); +} + +#[test] +fn infer_associated_method_generics_with_default_param() { + assert_snapshot!( + infer(r#" +struct Gen { + val: T +} + +impl Gen { + pub fn make() -> Gen { + loop { } + } +} + +fn test() { + let a = Gen::make(); +} +"#), + @r###" + [80; 104) '{ ... }': Gen + [90; 98) 'loop { }': ! + [95; 98) '{ }': () + [118; 146) '{ ...e(); }': () + [128; 129) 'a': Gen + [132; 141) 'Gen::make': fn make() -> Gen + [132; 143) 'Gen::make()': Gen + "### + ); +} + +#[test] +fn infer_associated_method_generics_with_default_tuple_param() { + let t = type_at( + r#" +//- /main.rs +struct Gen { + val: T +} + +impl Gen { + pub fn make() -> Gen { + loop { } + } +} + +fn test() { + let a = Gen::make(); + a.val<|>; +} +"#, + ); + assert_eq!(t, "()"); +} + +#[test] +fn infer_associated_method_generics_without_args() { + assert_snapshot!( + infer(r#" +struct Gen { + val: T +} + +impl Gen { + pub fn make() -> Gen { + loop { } + } +} + +fn test() { + let a = Gen::::make(); +} +"#), + @r###" + [76; 100) '{ ... }': Gen + [86; 94) 'loop { }': ! + [91; 94) '{ }': () + [114; 149) '{ ...e(); }': () + [124; 125) 'a': Gen + [128; 144) 'Gen::<...::make': fn make() -> Gen + [128; 146) 'Gen::<...make()': Gen + "### + ); +} + +#[test] +fn infer_associated_method_generics_2_type_params_without_args() { + assert_snapshot!( + infer(r#" +struct Gen { + val: T, + val2: U, +} + +impl Gen { + pub fn make() -> Gen { + loop { } + } +} + +fn test() { + let a = Gen::::make(); +} +"#), + @r###" + [102; 126) '{ ... }': Gen + [112; 120) 'loop { }': ! + [117; 120) '{ }': () + [140; 180) '{ ...e(); }': () + [150; 151) 'a': Gen + [154; 175) 'Gen::<...::make': fn make() -> Gen + [154; 177) 'Gen::<...make()': Gen + "### + ); +} + +#[test] +fn cross_crate_associated_method_call() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:other_crate +fn test() { + let x = other_crate::foo::S::thing(); + x<|>; +} + +//- /lib.rs crate:other_crate +mod foo { + struct S; + impl S { + fn thing() -> i128 {} + } +} +"#, + ); + assert_eq!("i128", type_at_pos(&db, pos)); +} + +#[test] +fn infer_trait_method_simple() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + assert_snapshot!( + infer(r#" +trait Trait1 { + fn method(&self) -> u32; +} +struct S1; +impl Trait1 for S1 {} +trait Trait2 { + fn method(&self) -> i128; +} +struct S2; +impl Trait2 for S2 {} +fn test() { + S1.method(); // -> u32 + S2.method(); // -> i128 +} +"#), + @r###" + [31; 35) 'self': &Self + [110; 114) 'self': &Self + [170; 228) '{ ...i128 }': () + [176; 178) 'S1': S1 + [176; 187) 'S1.method()': u32 + [203; 205) 'S2': S2 + [203; 214) 'S2.method()': i128 + "### + ); +} + +#[test] +fn infer_trait_method_scoped() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + assert_snapshot!( + infer(r#" +struct S; +mod foo { + pub trait Trait1 { + fn method(&self) -> u32; + } + impl Trait1 for super::S {} +} +mod bar { + pub trait Trait2 { + fn method(&self) -> i128; + } + impl Trait2 for super::S {} +} + +mod foo_test { + use super::S; + use super::foo::Trait1; + fn test() { + S.method(); // -> u32 + } +} + +mod bar_test { + use super::S; + use super::bar::Trait2; + fn test() { + S.method(); // -> i128 + } +} +"#), + @r###" + [63; 67) 'self': &Self + [169; 173) 'self': &Self + [300; 337) '{ ... }': () + [310; 311) 'S': S + [310; 320) 'S.method()': u32 + [416; 454) '{ ... }': () + [426; 427) 'S': S + [426; 436) 'S.method()': i128 + "### + ); +} + +#[test] +fn infer_trait_method_generic_1() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + assert_snapshot!( + infer(r#" +trait Trait { + fn method(&self) -> T; +} +struct S; +impl Trait for S {} +fn test() { + S.method(); +} +"#), + @r###" + [33; 37) 'self': &Self + [92; 111) '{ ...d(); }': () + [98; 99) 'S': S + [98; 108) 'S.method()': u32 + "### + ); +} + +#[test] +fn infer_trait_method_generic_more_params() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + assert_snapshot!( + infer(r#" +trait Trait { + fn method1(&self) -> (T1, T2, T3); + fn method2(&self) -> (T3, T2, T1); +} +struct S1; +impl Trait for S1 {} +struct S2; +impl Trait for S2 {} +fn test() { + S1.method1(); // u8, u16, u32 + S1.method2(); // u32, u16, u8 + S2.method1(); // i8, i16, {unknown} + S2.method2(); // {unknown}, i16, i8 +} +"#), + @r###" + [43; 47) 'self': &Self + [82; 86) 'self': &Self + [210; 361) '{ ..., i8 }': () + [216; 218) 'S1': S1 + [216; 228) 'S1.method1()': (u8, u16, u32) + [250; 252) 'S1': S1 + [250; 262) 'S1.method2()': (u32, u16, u8) + [284; 286) 'S2': S2 + [284; 296) 'S2.method1()': (i8, i16, {unknown}) + [324; 326) 'S2': S2 + [324; 336) 'S2.method2()': ({unknown}, i16, i8) + "### + ); +} + +#[test] +fn infer_trait_method_generic_2() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + assert_snapshot!( + infer(r#" +trait Trait { + fn method(&self) -> T; +} +struct S(T); +impl Trait for S {} +fn test() { + S(1u32).method(); +} +"#), + @r###" + [33; 37) 'self': &Self + [102; 127) '{ ...d(); }': () + [108; 109) 'S': S(T) -> S + [108; 115) 'S(1u32)': S + [108; 124) 'S(1u32...thod()': u32 + [110; 114) '1u32': u32 + "### + ); +} + +#[test] +fn infer_trait_assoc_method() { + assert_snapshot!( + infer(r#" +trait Default { + fn default() -> Self; +} +struct S; +impl Default for S {} +fn test() { + let s1: S = Default::default(); + let s2 = S::default(); + let s3 = ::default(); +} +"#), + @r###" + [87; 193) '{ ...t(); }': () + [97; 99) 's1': S + [105; 121) 'Defaul...efault': fn default() -> Self + [105; 123) 'Defaul...ault()': S + [133; 135) 's2': S + [138; 148) 'S::default': fn default() -> Self + [138; 150) 'S::default()': S + [160; 162) 's3': S + [165; 188) '() -> Self + [165; 190) ' { + fn make() -> T; +} +struct S; +impl Trait for S {} +struct G; +impl Trait for G {} +fn test() { + let a = S::make(); + let b = G::::make(); + let c: f64 = G::make(); +} +"#), + @r###" + [127; 211) '{ ...e(); }': () + [137; 138) 'a': u32 + [141; 148) 'S::make': fn make() -> T + [141; 150) 'S::make()': u32 + [160; 161) 'b': u64 + [164; 178) 'G::::make': fn make, u64>() -> T + [164; 180) 'G::, f64>() -> T + [199; 208) 'G::make()': f64 + "### + ); +} + +#[test] +fn infer_trait_assoc_method_generics_2() { + assert_snapshot!( + infer(r#" +trait Trait { + fn make() -> (T, U); +} +struct S; +impl Trait for S {} +struct G; +impl Trait for G {} +fn test() { + let a = S::make::(); + let b: (_, i64) = S::make(); + let c = G::::make::(); + let d: (u32, _) = G::make::(); + let e: (u32, i64) = G::make(); +} +"#), + @r###" + [135; 313) '{ ...e(); }': () + [145; 146) 'a': (u32, i64) + [149; 163) 'S::make::': fn make() -> (T, U) + [149; 165) 'S::mak...i64>()': (u32, i64) + [175; 176) 'b': (u32, i64) + [189; 196) 'S::make': fn make() -> (T, U) + [189; 198) 'S::make()': (u32, i64) + [208; 209) 'c': (u32, i64) + [212; 233) 'G::': fn make, u32, i64>() -> (T, U) + [212; 235) 'G::()': (u32, i64) + [245; 246) 'd': (u32, i64) + [259; 273) 'G::make::': fn make, u32, i64>() -> (T, U) + [259; 275) 'G::mak...i64>()': (u32, i64) + [285; 286) 'e': (u32, i64) + [301; 308) 'G::make': fn make, u32, i64>() -> (T, U) + [301; 310) 'G::make()': (u32, i64) + "### + ); +} + +#[test] +fn infer_trait_assoc_method_generics_3() { + assert_snapshot!( + infer(r#" +trait Trait { + fn make() -> (Self, T); +} +struct S; +impl Trait for S {} +fn test() { + let a = S::make(); +} +"#), + @r###" + [101; 127) '{ ...e(); }': () + [111; 112) 'a': (S, i64) + [115; 122) 'S::make': fn make, i64>() -> (Self, T) + [115; 124) 'S::make()': (S, i64) + "### + ); +} + +#[test] +fn infer_trait_assoc_method_generics_4() { + assert_snapshot!( + infer(r#" +trait Trait { + fn make() -> (Self, T); +} +struct S; +impl Trait for S {} +impl Trait for S {} +fn test() { + let a: (S, _) = S::make(); + let b: (_, i32) = S::make(); +} +"#), + @r###" + [131; 203) '{ ...e(); }': () + [141; 142) 'a': (S, i64) + [158; 165) 'S::make': fn make, i64>() -> (Self, T) + [158; 167) 'S::make()': (S, i64) + [177; 178) 'b': (S, i32) + [191; 198) 'S::make': fn make, i32>() -> (Self, T) + [191; 200) 'S::make()': (S, i32) + "### + ); +} + +#[test] +fn infer_trait_assoc_method_generics_5() { + assert_snapshot!( + infer(r#" +trait Trait { + fn make() -> (Self, T, U); +} +struct S; +impl Trait for S {} +fn test() { + let a = >::make::(); + let b: (S, _, _) = Trait::::make::(); +} +"#), + @r###" + [107; 211) '{ ...>(); }': () + [117; 118) 'a': (S, i64, u8) + [121; 150) '': fn make, i64, u8>() -> (Self, T, U) + [121; 152) '()': (S, i64, u8) + [162; 163) 'b': (S, i64, u8) + [182; 206) 'Trait:...::': fn make, i64, u8>() -> (Self, T, U) + [182; 208) 'Trait:...()': (S, i64, u8) + "### + ); +} + +#[test] +fn infer_call_trait_method_on_generic_param_1() { + assert_snapshot!( + infer(r#" +trait Trait { + fn method(&self) -> u32; +} +fn test(t: T) { + t.method(); +} +"#), + @r###" + [30; 34) 'self': &Self + [64; 65) 't': T + [70; 89) '{ ...d(); }': () + [76; 77) 't': T + [76; 86) 't.method()': u32 + "### + ); +} + +#[test] +fn infer_call_trait_method_on_generic_param_2() { + assert_snapshot!( + infer(r#" +trait Trait { + fn method(&self) -> T; +} +fn test>(t: T) { + t.method(); +} +"#), + @r###" + [33; 37) 'self': &Self + [71; 72) 't': T + [77; 96) '{ ...d(); }': () + [83; 84) 't': T + [83; 93) 't.method()': [missing name] + "### + ); +} + +#[test] +fn infer_with_multiple_trait_impls() { + assert_snapshot!( + infer(r#" +trait Into { + fn into(self) -> T; +} +struct S; +impl Into for S {} +impl Into for S {} +fn test() { + let x: u32 = S.into(); + let y: u64 = S.into(); + let z = Into::::into(S); +} +"#), + @r###" + [29; 33) 'self': Self + [111; 202) '{ ...(S); }': () + [121; 122) 'x': u32 + [130; 131) 'S': S + [130; 138) 'S.into()': u32 + [148; 149) 'y': u64 + [157; 158) 'S': S + [157; 165) 'S.into()': u64 + [175; 176) 'z': u64 + [179; 196) 'Into::...::into': fn into(Self) -> T + [179; 199) 'Into::...nto(S)': u64 + [197; 198) 'S': S + "### + ); +} + +#[test] +fn method_resolution_unify_impl_self_type() { + let t = type_at( + r#" +//- /main.rs +struct S; +impl S { fn foo(&self) -> u8 {} } +impl S { fn foo(&self) -> i8 {} } +fn test() { (S::.foo(), S::.foo())<|>; } +"#, + ); + assert_eq!(t, "(u8, i8)"); +} + +#[test] +fn method_resolution_trait_before_autoref() { + let t = type_at( + r#" +//- /main.rs +trait Trait { fn foo(self) -> u128; } +struct S; +impl S { fn foo(&self) -> i8 { 0 } } +impl Trait for S { fn foo(self) -> u128 { 0 } } +fn test() { S.foo()<|>; } +"#, + ); + assert_eq!(t, "u128"); +} + +#[test] +fn method_resolution_by_value_before_autoref() { + let t = type_at( + r#" +//- /main.rs +trait Clone { fn clone(&self) -> Self; } +struct S; +impl Clone for S {} +impl Clone for &S {} +fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; } +"#, + ); + assert_eq!(t, "(S, S, &S)"); +} + +#[test] +fn method_resolution_trait_before_autoderef() { + let t = type_at( + r#" +//- /main.rs +trait Trait { fn foo(self) -> u128; } +struct S; +impl S { fn foo(self) -> i8 { 0 } } +impl Trait for &S { fn foo(self) -> u128 { 0 } } +fn test() { (&S).foo()<|>; } +"#, + ); + assert_eq!(t, "u128"); +} + +#[test] +fn method_resolution_impl_before_trait() { + let t = type_at( + r#" +//- /main.rs +trait Trait { fn foo(self) -> u128; } +struct S; +impl S { fn foo(self) -> i8 { 0 } } +impl Trait for S { fn foo(self) -> u128 { 0 } } +fn test() { S.foo()<|>; } +"#, + ); + assert_eq!(t, "i8"); +} + +#[test] +fn method_resolution_impl_ref_before_trait() { + let t = type_at( + r#" +//- /main.rs +trait Trait { fn foo(self) -> u128; } +struct S; +impl S { fn foo(&self) -> i8 { 0 } } +impl Trait for &S { fn foo(self) -> u128 { 0 } } +fn test() { S.foo()<|>; } +"#, + ); + assert_eq!(t, "i8"); +} + +#[test] +fn method_resolution_trait_autoderef() { + let t = type_at( + r#" +//- /main.rs +trait Trait { fn foo(self) -> u128; } +struct S; +impl Trait for S { fn foo(self) -> u128 { 0 } } +fn test() { (&S).foo()<|>; } +"#, + ); + assert_eq!(t, "u128"); +} + +#[test] +fn method_resolution_trait_from_prelude() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:other_crate +struct S; +impl Clone for S {} + +fn test() { + S.clone()<|>; +} + +//- /lib.rs crate:other_crate +#[prelude_import] use foo::*; + +mod foo { + trait Clone { + fn clone(&self) -> Self; + } +} +"#, + ); + assert_eq!("S", type_at_pos(&db, pos)); +} + +#[test] +fn method_resolution_where_clause_for_unknown_trait() { + // The blanket impl shouldn't apply because we can't even resolve UnknownTrait + let t = type_at( + r#" +//- /main.rs +trait Trait { fn foo(self) -> u128; } +struct S; +impl Trait for T where T: UnknownTrait {} +fn test() { (&S).foo()<|>; } +"#, + ); + assert_eq!(t, "{unknown}"); +} + +#[test] +fn method_resolution_where_clause_not_met() { + // The blanket impl shouldn't apply because we can't prove S: Clone + let t = type_at( + r#" +//- /main.rs +trait Clone {} +trait Trait { fn foo(self) -> u128; } +struct S; +impl Trait for T where T: Clone {} +fn test() { (&S).foo()<|>; } +"#, + ); + // This is also to make sure that we don't resolve to the foo method just + // because that's the only method named foo we can find, which would make + // the below tests not work + assert_eq!(t, "{unknown}"); +} + +#[test] +fn method_resolution_where_clause_inline_not_met() { + // The blanket impl shouldn't apply because we can't prove S: Clone + let t = type_at( + r#" +//- /main.rs +trait Clone {} +trait Trait { fn foo(self) -> u128; } +struct S; +impl Trait for T {} +fn test() { (&S).foo()<|>; } +"#, + ); + assert_eq!(t, "{unknown}"); +} + +#[test] +fn method_resolution_where_clause_1() { + let t = type_at( + r#" +//- /main.rs +trait Clone {} +trait Trait { fn foo(self) -> u128; } +struct S; +impl Clone for S {} +impl Trait for T where T: Clone {} +fn test() { S.foo()<|>; } +"#, + ); + assert_eq!(t, "u128"); +} + +#[test] +fn method_resolution_where_clause_2() { + let t = type_at( + r#" +//- /main.rs +trait Into { fn into(self) -> T; } +trait From { fn from(other: T) -> Self; } +struct S1; +struct S2; +impl From for S1 {} +impl Into for T where U: From {} +fn test() { S2.into()<|>; } +"#, + ); + assert_eq!(t, "{unknown}"); +} + +#[test] +fn method_resolution_where_clause_inline() { + let t = type_at( + r#" +//- /main.rs +trait Into { fn into(self) -> T; } +trait From { fn from(other: T) -> Self; } +struct S1; +struct S2; +impl From for S1 {} +impl> Into for T {} +fn test() { S2.into()<|>; } +"#, + ); + assert_eq!(t, "{unknown}"); +} + +#[test] +fn method_resolution_encountering_fn_type() { + type_at( + r#" +//- /main.rs +fn foo() {} +trait FnOnce { fn call(self); } +fn test() { foo.call()<|>; } +"#, + ); +} + +#[test] +fn method_resolution_slow() { + // this can get quite slow if we set the solver size limit too high + let t = type_at( + r#" +//- /main.rs +trait SendX {} + +struct S1; impl SendX for S1 {} +struct S2; impl SendX for S2 {} +struct U1; + +trait Trait { fn method(self); } + +struct X1 {} +impl SendX for X1 where A: SendX, B: SendX {} + +struct S {} + +trait FnX {} + +impl Trait for S where C: FnX, B: SendX {} + +fn test() { (S {}).method()<|>; } +"#, + ); + assert_eq!(t, "()"); +} diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs new file mode 100644 index 000000000..cb3890b42 --- /dev/null +++ b/crates/ra_hir_ty/src/tests/patterns.rs @@ -0,0 +1,238 @@ +use super::infer; +use insta::assert_snapshot; +use test_utils::covers; + +#[test] +fn infer_pattern() { + assert_snapshot!( + infer(r#" +fn test(x: &i32) { + let y = x; + let &z = x; + let a = z; + let (c, d) = (1, "hello"); + + for (e, f) in some_iter { + let g = e; + } + + if let [val] = opt { + let h = val; + } + + let lambda = |a: u64, b, c: i32| { a + b; c }; + + let ref ref_to_x = x; + let mut mut_x = x; + let ref mut mut_ref_to_x = x; + let k = mut_ref_to_x; +} +"#), + @r###" + [9; 10) 'x': &i32 + [18; 369) '{ ...o_x; }': () + [28; 29) 'y': &i32 + [32; 33) 'x': &i32 + [43; 45) '&z': &i32 + [44; 45) 'z': i32 + [48; 49) 'x': &i32 + [59; 60) 'a': i32 + [63; 64) 'z': i32 + [74; 80) '(c, d)': (i32, &str) + [75; 76) 'c': i32 + [78; 79) 'd': &str + [83; 95) '(1, "hello")': (i32, &str) + [84; 85) '1': i32 + [87; 94) '"hello"': &str + [102; 152) 'for (e... }': () + [106; 112) '(e, f)': ({unknown}, {unknown}) + [107; 108) 'e': {unknown} + [110; 111) 'f': {unknown} + [116; 125) 'some_iter': {unknown} + [126; 152) '{ ... }': () + [140; 141) 'g': {unknown} + [144; 145) 'e': {unknown} + [158; 205) 'if let... }': () + [165; 170) '[val]': {unknown} + [173; 176) 'opt': {unknown} + [177; 205) '{ ... }': () + [191; 192) 'h': {unknown} + [195; 198) 'val': {unknown} + [215; 221) 'lambda': |u64, u64, i32| -> i32 + [224; 256) '|a: u6...b; c }': |u64, u64, i32| -> i32 + [225; 226) 'a': u64 + [233; 234) 'b': u64 + [236; 237) 'c': i32 + [244; 256) '{ a + b; c }': i32 + [246; 247) 'a': u64 + [246; 251) 'a + b': u64 + [250; 251) 'b': u64 + [253; 254) 'c': i32 + [267; 279) 'ref ref_to_x': &&i32 + [282; 283) 'x': &i32 + [293; 302) 'mut mut_x': &i32 + [305; 306) 'x': &i32 + [316; 336) 'ref mu...f_to_x': &mut &i32 + [339; 340) 'x': &i32 + [350; 351) 'k': &mut &i32 + [354; 366) 'mut_ref_to_x': &mut &i32 + "### + ); +} + +#[test] +fn infer_pattern_match_ergonomics() { + assert_snapshot!( + infer(r#" +struct A(T); + +fn test() { + let A(n) = &A(1); + let A(n) = &mut A(1); +} +"#), + @r###" + [28; 79) '{ ...(1); }': () + [38; 42) 'A(n)': A + [40; 41) 'n': &i32 + [45; 50) '&A(1)': &A + [46; 47) 'A': A(T) -> A + [46; 50) 'A(1)': A + [48; 49) '1': i32 + [60; 64) 'A(n)': A + [62; 63) 'n': &mut i32 + [67; 76) '&mut A(1)': &mut A + [72; 73) 'A': A(T) -> A + [72; 76) 'A(1)': A + [74; 75) '1': i32 + "### + ); +} + +#[test] +fn infer_pattern_match_ergonomics_ref() { + covers!(match_ergonomics_ref); + assert_snapshot!( + infer(r#" +fn test() { + let v = &(1, &2); + let (_, &w) = v; +} +"#), + @r###" + [11; 57) '{ ...= v; }': () + [21; 22) 'v': &(i32, &i32) + [25; 33) '&(1, &2)': &(i32, &i32) + [26; 33) '(1, &2)': (i32, &i32) + [27; 28) '1': i32 + [30; 32) '&2': &i32 + [31; 32) '2': i32 + [43; 50) '(_, &w)': (i32, &i32) + [44; 45) '_': i32 + [47; 49) '&w': &i32 + [48; 49) 'w': i32 + [53; 54) 'v': &(i32, &i32) + "### + ); +} + +#[test] +fn infer_adt_pattern() { + assert_snapshot!( + infer(r#" +enum E { + A { x: usize }, + B +} + +struct S(u32, E); + +fn test() { + let e = E::A { x: 3 }; + + let S(y, z) = foo; + let E::A { x: new_var } = e; + + match e { + E::A { x } => x, + E::B if foo => 1, + E::B => 10, + }; + + let ref d @ E::A { .. } = e; + d; +} +"#), + @r###" + [68; 289) '{ ... d; }': () + [78; 79) 'e': E + [82; 95) 'E::A { x: 3 }': E + [92; 93) '3': usize + [106; 113) 'S(y, z)': S + [108; 109) 'y': u32 + [111; 112) 'z': E + [116; 119) 'foo': S + [129; 148) 'E::A {..._var }': E + [139; 146) 'new_var': usize + [151; 152) 'e': E + [159; 245) 'match ... }': usize + [165; 166) 'e': E + [177; 187) 'E::A { x }': E + [184; 185) 'x': usize + [191; 192) 'x': usize + [202; 206) 'E::B': E + [210; 213) 'foo': bool + [217; 218) '1': usize + [228; 232) 'E::B': E + [236; 238) '10': usize + [256; 275) 'ref d ...{ .. }': &E + [264; 275) 'E::A { .. }': E + [278; 279) 'e': E + [285; 286) 'd': &E + "### + ); +} + +#[test] +fn infer_generics_in_patterns() { + assert_snapshot!( + infer(r#" +struct A { + x: T, +} + +enum Option { + Some(T), + None, +} + +fn test(a1: A, o: Option) { + let A { x: x2 } = a1; + let A:: { x: x3 } = A { x: 1 }; + match o { + Option::Some(t) => t, + _ => 1, + }; +} +"#), + @r###" + [79; 81) 'a1': A + [91; 92) 'o': Option + [107; 244) '{ ... }; }': () + [117; 128) 'A { x: x2 }': A + [124; 126) 'x2': u32 + [131; 133) 'a1': A + [143; 161) 'A:: + [157; 159) 'x3': i64 + [164; 174) 'A { x: 1 }': A + [171; 172) '1': i64 + [180; 241) 'match ... }': u64 + [186; 187) 'o': Option + [198; 213) 'Option::Some(t)': Option + [211; 212) 't': u64 + [217; 218) 't': u64 + [228; 229) '_': Option + [233; 234) '1': u64 + "### + ); +} diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs new file mode 100644 index 000000000..09d684ac2 --- /dev/null +++ b/crates/ra_hir_ty/src/tests/regression.rs @@ -0,0 +1,333 @@ +use super::infer; +use insta::assert_snapshot; +use test_utils::covers; + +#[test] +fn bug_484() { + assert_snapshot!( + infer(r#" +fn test() { + let x = if true {}; +} +"#), + @r###" + [11; 37) '{ l... {}; }': () + [20; 21) 'x': () + [24; 34) 'if true {}': () + [27; 31) 'true': bool + [32; 34) '{}': () + "### + ); +} + +#[test] +fn no_panic_on_field_of_enum() { + assert_snapshot!( + infer(r#" +enum X {} + +fn test(x: X) { + x.some_field; +} +"#), + @r###" + [20; 21) 'x': X + [26; 47) '{ ...eld; }': () + [32; 33) 'x': X + [32; 44) 'x.some_field': {unknown} + "### + ); +} + +#[test] +fn bug_585() { + assert_snapshot!( + infer(r#" +fn test() { + X {}; + match x { + A::B {} => (), + A::Y() => (), + } +} +"#), + @r###" + [11; 89) '{ ... } }': () + [17; 21) 'X {}': {unknown} + [27; 87) 'match ... }': () + [33; 34) 'x': {unknown} + [45; 52) 'A::B {}': {unknown} + [56; 58) '()': () + [68; 74) 'A::Y()': {unknown} + [78; 80) '()': () + "### + ); +} + +#[test] +fn bug_651() { + assert_snapshot!( + infer(r#" +fn quux() { + let y = 92; + 1 + y; +} +"#), + @r###" + [11; 41) '{ ...+ y; }': () + [21; 22) 'y': i32 + [25; 27) '92': i32 + [33; 34) '1': i32 + [33; 38) '1 + y': i32 + [37; 38) 'y': i32 + "### + ); +} + +#[test] +fn recursive_vars() { + covers!(type_var_cycles_resolve_completely); + covers!(type_var_cycles_resolve_as_possible); + assert_snapshot!( + infer(r#" +fn test() { + let y = unknown; + [y, &y]; +} +"#), + @r###" + [11; 48) '{ ...&y]; }': () + [21; 22) 'y': &{unknown} + [25; 32) 'unknown': &{unknown} + [38; 45) '[y, &y]': [&&{unknown};_] + [39; 40) 'y': &{unknown} + [42; 44) '&y': &&{unknown} + [43; 44) 'y': &{unknown} + "### + ); +} + +#[test] +fn recursive_vars_2() { + covers!(type_var_cycles_resolve_completely); + covers!(type_var_cycles_resolve_as_possible); + assert_snapshot!( + infer(r#" +fn test() { + let x = unknown; + let y = unknown; + [(x, y), (&y, &x)]; +} +"#), + @r###" + [11; 80) '{ ...x)]; }': () + [21; 22) 'x': &&{unknown} + [25; 32) 'unknown': &&{unknown} + [42; 43) 'y': &&{unknown} + [46; 53) 'unknown': &&{unknown} + [59; 77) '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown});_] + [60; 66) '(x, y)': (&&&{unknown}, &&&{unknown}) + [61; 62) 'x': &&{unknown} + [64; 65) 'y': &&{unknown} + [68; 76) '(&y, &x)': (&&&{unknown}, &&&{unknown}) + [69; 71) '&y': &&&{unknown} + [70; 71) 'y': &&{unknown} + [73; 75) '&x': &&&{unknown} + [74; 75) 'x': &&{unknown} + "### + ); +} + +#[test] +fn infer_std_crash_1() { + // caused stack overflow, taken from std + assert_snapshot!( + infer(r#" +enum Maybe { + Real(T), + Fake, +} + +fn write() { + match something_unknown { + Maybe::Real(ref mut something) => (), + } +} +"#), + @r###" + [54; 139) '{ ... } }': () + [60; 137) 'match ... }': () + [66; 83) 'someth...nknown': Maybe<{unknown}> + [94; 124) 'Maybe:...thing)': Maybe<{unknown}> + [106; 123) 'ref mu...ething': &mut {unknown} + [128; 130) '()': () + "### + ); +} + +#[test] +fn infer_std_crash_2() { + covers!(type_var_resolves_to_int_var); + // caused "equating two type variables, ...", taken from std + assert_snapshot!( + infer(r#" +fn test_line_buffer() { + &[0, b'\n', 1, b'\n']; +} +"#), + @r###" + [23; 53) '{ ...n']; }': () + [29; 50) '&[0, b...b'\n']': &[u8;_] + [30; 50) '[0, b'...b'\n']': [u8;_] + [31; 32) '0': u8 + [34; 39) 'b'\n'': u8 + [41; 42) '1': u8 + [44; 49) 'b'\n'': u8 + "### + ); +} + +#[test] +fn infer_std_crash_3() { + // taken from rustc + assert_snapshot!( + infer(r#" +pub fn compute() { + match nope!() { + SizeSkeleton::Pointer { non_zero: true, tail } => {} + } +} +"#), + @r###" + [18; 108) '{ ... } }': () + [24; 106) 'match ... }': () + [30; 37) 'nope!()': {unknown} + [48; 94) 'SizeSk...tail }': {unknown} + [82; 86) 'true': {unknown} + [88; 92) 'tail': {unknown} + [98; 100) '{}': () + "### + ); +} + +#[test] +fn infer_std_crash_4() { + // taken from rustc + assert_snapshot!( + infer(r#" +pub fn primitive_type() { + match *self { + BorrowedRef { type_: Primitive(p), ..} => {}, + } +} +"#), + @r###" + [25; 106) '{ ... } }': () + [31; 104) 'match ... }': () + [37; 42) '*self': {unknown} + [38; 42) 'self': {unknown} + [53; 91) 'Borrow...), ..}': {unknown} + [74; 86) 'Primitive(p)': {unknown} + [84; 85) 'p': {unknown} + [95; 97) '{}': () + "### + ); +} + +#[test] +fn infer_std_crash_5() { + // taken from rustc + assert_snapshot!( + infer(r#" +fn extra_compiler_flags() { + for content in doesnt_matter { + let name = if doesnt_matter { + first + } else { + &content + }; + + let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { + name + } else { + content + }; + } +} +"#), + @r###" + [27; 323) '{ ... } }': () + [33; 321) 'for co... }': () + [37; 44) 'content': &{unknown} + [48; 61) 'doesnt_matter': {unknown} + [62; 321) '{ ... }': () + [76; 80) 'name': &&{unknown} + [83; 167) 'if doe... }': &&{unknown} + [86; 99) 'doesnt_matter': bool + [100; 129) '{ ... }': &&{unknown} + [114; 119) 'first': &&{unknown} + [135; 167) '{ ... }': &&{unknown} + [149; 157) '&content': &&{unknown} + [150; 157) 'content': &{unknown} + [182; 189) 'content': &{unknown} + [192; 314) 'if ICE... }': &{unknown} + [195; 232) 'ICE_RE..._VALUE': {unknown} + [195; 248) 'ICE_RE...&name)': bool + [242; 247) '&name': &&&{unknown} + [243; 247) 'name': &&{unknown} + [249; 277) '{ ... }': &&{unknown} + [263; 267) 'name': &&{unknown} + [283; 314) '{ ... }': &{unknown} + [297; 304) 'content': &{unknown} + "### + ); +} + +#[test] +fn infer_nested_generics_crash() { + // another crash found typechecking rustc + assert_snapshot!( + infer(r#" +struct Canonical { + value: V, +} +struct QueryResponse { + value: V, +} +fn test(query_response: Canonical>) { + &query_response.value; +} +"#), + @r###" + [92; 106) 'query_response': Canonical> + [137; 167) '{ ...lue; }': () + [143; 164) '&query....value': &QueryResponse + [144; 158) 'query_response': Canonical> + [144; 164) 'query_....value': QueryResponse + "### + ); +} + +#[test] +fn bug_1030() { + assert_snapshot!(infer(r#" +struct HashSet; +struct FxHasher; +type FxHashSet = HashSet; + +impl HashSet { + fn default() -> HashSet {} +} + +pub fn main_loop() { + FxHashSet::default(); +} +"#), + @r###" + [144; 146) '{}': () + [169; 198) '{ ...t(); }': () + [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet + [175; 195) 'FxHash...ault()': HashSet<{unknown}, FxHasher> + "### + ); +} diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs new file mode 100644 index 000000000..18976c9ae --- /dev/null +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -0,0 +1,1608 @@ +use super::{infer, type_at, type_at_pos}; +use crate::test_db::TestDB; +use insta::assert_snapshot; +use ra_db::fixture::WithFixture; + +#[test] +fn infer_box() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std + +fn test() { + let x = box 1; + let t = (x, box x, box &1, box [1]); + t<|>; +} + +//- /std.rs crate:std +#[prelude_import] use prelude::*; +mod prelude {} + +mod boxed { + pub struct Box { + inner: *mut T, + } +} + +"#, + ); + assert_eq!("(Box, Box>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos)); +} + +#[test] +fn infer_adt_self() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs +enum Nat { Succ(Self), Demo(Nat), Zero } + +fn test() { + let foo: Nat = Nat::Zero; + if let Nat::Succ(x) = foo { + x<|> + } +} + +"#, + ); + assert_eq!("Nat", type_at_pos(&db, pos)); +} + +#[test] +fn infer_ranges() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std +fn test() { + let a = ..; + let b = 1..; + let c = ..2u32; + let d = 1..2usize; + let e = ..=10; + let f = 'a'..='z'; + + let t = (a, b, c, d, e, f); + t<|>; +} + +//- /std.rs crate:std +#[prelude_import] use prelude::*; +mod prelude {} + +pub mod ops { + pub struct Range { + pub start: Idx, + pub end: Idx, + } + pub struct RangeFrom { + pub start: Idx, + } + struct RangeFull; + pub struct RangeInclusive { + start: Idx, + end: Idx, + is_empty: u8, + } + pub struct RangeTo { + pub end: Idx, + } + pub struct RangeToInclusive { + pub end: Idx, + } +} +"#, + ); + assert_eq!( + "(RangeFull, RangeFrom, RangeTo, Range, RangeToInclusive, RangeInclusive)", + type_at_pos(&db, pos), + ); +} + +#[test] +fn infer_while_let() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs +enum Option { Some(T), None } + +fn test() { + let foo: Option = None; + while let Option::Some(x) = foo { + <|>x + } +} + +"#, + ); + assert_eq!("f32", type_at_pos(&db, pos)); +} + +#[test] +fn infer_basics() { + assert_snapshot!( + infer(r#" +fn test(a: u32, b: isize, c: !, d: &str) { + a; + b; + c; + d; + 1usize; + 1isize; + "test"; + 1.0f32; +}"#), + @r###" + [9; 10) 'a': u32 + [17; 18) 'b': isize + [27; 28) 'c': ! + [33; 34) 'd': &str + [42; 121) '{ ...f32; }': ! + [48; 49) 'a': u32 + [55; 56) 'b': isize + [62; 63) 'c': ! + [69; 70) 'd': &str + [76; 82) '1usize': usize + [88; 94) '1isize': isize + [100; 106) '"test"': &str + [112; 118) '1.0f32': f32 + "### + ); +} + +#[test] +fn infer_let() { + assert_snapshot!( + infer(r#" +fn test() { + let a = 1isize; + let b: usize = 1; + let c = b; + let d: u32; + let e; + let f: i32 = e; +} +"#), + @r###" + [11; 118) '{ ...= e; }': () + [21; 22) 'a': isize + [25; 31) '1isize': isize + [41; 42) 'b': usize + [52; 53) '1': usize + [63; 64) 'c': usize + [67; 68) 'b': usize + [78; 79) 'd': u32 + [94; 95) 'e': i32 + [105; 106) 'f': i32 + [114; 115) 'e': i32 + "### + ); +} + +#[test] +fn infer_paths() { + assert_snapshot!( + infer(r#" +fn a() -> u32 { 1 } + +mod b { + fn c() -> u32 { 1 } +} + +fn test() { + a(); + b::c(); +} +"#), + @r###" + [15; 20) '{ 1 }': u32 + [17; 18) '1': u32 + [48; 53) '{ 1 }': u32 + [50; 51) '1': u32 + [67; 91) '{ ...c(); }': () + [73; 74) 'a': fn a() -> u32 + [73; 76) 'a()': u32 + [82; 86) 'b::c': fn c() -> u32 + [82; 88) 'b::c()': u32 + "### + ); +} + +#[test] +fn infer_path_type() { + assert_snapshot!( + infer(r#" +struct S; + +impl S { + fn foo() -> i32 { 1 } +} + +fn test() { + S::foo(); + ::foo(); +} +"#), + @r###" + [41; 46) '{ 1 }': i32 + [43; 44) '1': i32 + [60; 93) '{ ...o(); }': () + [66; 72) 'S::foo': fn foo() -> i32 + [66; 74) 'S::foo()': i32 + [80; 88) '::foo': fn foo() -> i32 + [80; 90) '::foo()': i32 + "### + ); +} + +#[test] +fn infer_struct() { + assert_snapshot!( + infer(r#" +struct A { + b: B, + c: C, +} +struct B; +struct C(usize); + +fn test() { + let c = C(1); + B; + let a: A = A { b: B, c: C(1) }; + a.b; + a.c; +} +"#), + @r###" + [72; 154) '{ ...a.c; }': () + [82; 83) 'c': C + [86; 87) 'C': C(usize) -> C + [86; 90) 'C(1)': C + [88; 89) '1': usize + [96; 97) 'B': B + [107; 108) 'a': A + [114; 133) 'A { b:...C(1) }': A + [121; 122) 'B': B + [127; 128) 'C': C(usize) -> C + [127; 131) 'C(1)': C + [129; 130) '1': usize + [139; 140) 'a': A + [139; 142) 'a.b': B + [148; 149) 'a': A + [148; 151) 'a.c': C + "### + ); +} + +#[test] +fn infer_enum() { + assert_snapshot!( + infer(r#" +enum E { + V1 { field: u32 }, + V2 +} +fn test() { + E::V1 { field: 1 }; + E::V2; +}"#), + @r###" + [48; 82) '{ E:...:V2; }': () + [52; 70) 'E::V1 ...d: 1 }': E + [67; 68) '1': u32 + [74; 79) 'E::V2': E + "### + ); +} + +#[test] +fn infer_refs() { + assert_snapshot!( + infer(r#" +fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { + a; + *a; + &a; + &mut a; + b; + *b; + &b; + c; + *c; + d; + *d; +} +"#), + @r###" + [9; 10) 'a': &u32 + [18; 19) 'b': &mut u32 + [31; 32) 'c': *const u32 + [46; 47) 'd': *mut u32 + [59; 150) '{ ... *d; }': () + [65; 66) 'a': &u32 + [72; 74) '*a': u32 + [73; 74) 'a': &u32 + [80; 82) '&a': &&u32 + [81; 82) 'a': &u32 + [88; 94) '&mut a': &mut &u32 + [93; 94) 'a': &u32 + [100; 101) 'b': &mut u32 + [107; 109) '*b': u32 + [108; 109) 'b': &mut u32 + [115; 117) '&b': &&mut u32 + [116; 117) 'b': &mut u32 + [123; 124) 'c': *const u32 + [130; 132) '*c': u32 + [131; 132) 'c': *const u32 + [138; 139) 'd': *mut u32 + [145; 147) '*d': u32 + [146; 147) 'd': *mut u32 + "### + ); +} + +#[test] +fn infer_literals() { + assert_snapshot!( + infer(r##" +fn test() { + 5i32; + 5f32; + 5f64; + "hello"; + b"bytes"; + 'c'; + b'b'; + 3.14; + 5000; + false; + true; + r#" + //! doc + // non-doc + mod foo {} + "#; + br#"yolo"#; +} +"##), + @r###" + [11; 221) '{ ...o"#; }': () + [17; 21) '5i32': i32 + [27; 31) '5f32': f32 + [37; 41) '5f64': f64 + [47; 54) '"hello"': &str + [60; 68) 'b"bytes"': &[u8] + [74; 77) ''c'': char + [83; 87) 'b'b'': u8 + [93; 97) '3.14': f64 + [103; 107) '5000': i32 + [113; 118) 'false': bool + [124; 128) 'true': bool + [134; 202) 'r#" ... "#': &str + [208; 218) 'br#"yolo"#': &[u8] + "### + ); +} + +#[test] +fn infer_unary_op() { + assert_snapshot!( + infer(r#" +enum SomeType {} + +fn test(x: SomeType) { + let b = false; + let c = !b; + let a = 100; + let d: i128 = -a; + let e = -100; + let f = !!!true; + let g = !42; + let h = !10u32; + let j = !a; + -3.14; + !3; + -x; + !x; + -"hello"; + !"hello"; +} +"#), + @r###" + [27; 28) 'x': SomeType + [40; 272) '{ ...lo"; }': () + [50; 51) 'b': bool + [54; 59) 'false': bool + [69; 70) 'c': bool + [73; 75) '!b': bool + [74; 75) 'b': bool + [85; 86) 'a': i128 + [89; 92) '100': i128 + [102; 103) 'd': i128 + [112; 114) '-a': i128 + [113; 114) 'a': i128 + [124; 125) 'e': i32 + [128; 132) '-100': i32 + [129; 132) '100': i32 + [142; 143) 'f': bool + [146; 153) '!!!true': bool + [147; 153) '!!true': bool + [148; 153) '!true': bool + [149; 153) 'true': bool + [163; 164) 'g': i32 + [167; 170) '!42': i32 + [168; 170) '42': i32 + [180; 181) 'h': u32 + [184; 190) '!10u32': u32 + [185; 190) '10u32': u32 + [200; 201) 'j': i128 + [204; 206) '!a': i128 + [205; 206) 'a': i128 + [212; 217) '-3.14': f64 + [213; 217) '3.14': f64 + [223; 225) '!3': i32 + [224; 225) '3': i32 + [231; 233) '-x': {unknown} + [232; 233) 'x': SomeType + [239; 241) '!x': {unknown} + [240; 241) 'x': SomeType + [247; 255) '-"hello"': {unknown} + [248; 255) '"hello"': &str + [261; 269) '!"hello"': {unknown} + [262; 269) '"hello"': &str + "### + ); +} + +#[test] +fn infer_backwards() { + assert_snapshot!( + infer(r#" +fn takes_u32(x: u32) {} + +struct S { i32_field: i32 } + +fn test() -> &mut &f64 { + let a = unknown_function(); + takes_u32(a); + let b = unknown_function(); + S { i32_field: b }; + let c = unknown_function(); + &mut &c +} +"#), + @r###" + [14; 15) 'x': u32 + [22; 24) '{}': () + [78; 231) '{ ...t &c }': &mut &f64 + [88; 89) 'a': u32 + [92; 108) 'unknow...nction': {unknown} + [92; 110) 'unknow...tion()': u32 + [116; 125) 'takes_u32': fn takes_u32(u32) -> () + [116; 128) 'takes_u32(a)': () + [126; 127) 'a': u32 + [138; 139) 'b': i32 + [142; 158) 'unknow...nction': {unknown} + [142; 160) 'unknow...tion()': i32 + [166; 184) 'S { i3...d: b }': S + [181; 182) 'b': i32 + [194; 195) 'c': f64 + [198; 214) 'unknow...nction': {unknown} + [198; 216) 'unknow...tion()': f64 + [222; 229) '&mut &c': &mut &f64 + [227; 229) '&c': &f64 + [228; 229) 'c': f64 + "### + ); +} + +#[test] +fn infer_self() { + assert_snapshot!( + infer(r#" +struct S; + +impl S { + fn test(&self) { + self; + } + fn test2(self: &Self) { + self; + } + fn test3() -> Self { + S {} + } + fn test4() -> Self { + Self {} + } +} +"#), + @r###" + [34; 38) 'self': &S + [40; 61) '{ ... }': () + [50; 54) 'self': &S + [75; 79) 'self': &S + [88; 109) '{ ... }': () + [98; 102) 'self': &S + [133; 153) '{ ... }': S + [143; 147) 'S {}': S + [177; 200) '{ ... }': S + [187; 194) 'Self {}': S + "### + ); +} + +#[test] +fn infer_binary_op() { + assert_snapshot!( + infer(r#" +fn f(x: bool) -> i32 { + 0i32 +} + +fn test() -> bool { + let x = a && b; + let y = true || false; + let z = x == y; + let t = x != y; + let minus_forty: isize = -40isize; + let h = minus_forty <= CONST_2; + let c = f(z || y) + 5; + let d = b; + let g = minus_forty ^= i; + let ten: usize = 10; + let ten_is_eleven = ten == some_num; + + ten < 3 +} +"#), + @r###" + [6; 7) 'x': bool + [22; 34) '{ 0i32 }': i32 + [28; 32) '0i32': i32 + [54; 370) '{ ... < 3 }': bool + [64; 65) 'x': bool + [68; 69) 'a': bool + [68; 74) 'a && b': bool + [73; 74) 'b': bool + [84; 85) 'y': bool + [88; 92) 'true': bool + [88; 101) 'true || false': bool + [96; 101) 'false': bool + [111; 112) 'z': bool + [115; 116) 'x': bool + [115; 121) 'x == y': bool + [120; 121) 'y': bool + [131; 132) 't': bool + [135; 136) 'x': bool + [135; 141) 'x != y': bool + [140; 141) 'y': bool + [151; 162) 'minus_forty': isize + [172; 180) '-40isize': isize + [173; 180) '40isize': isize + [190; 191) 'h': bool + [194; 205) 'minus_forty': isize + [194; 216) 'minus_...ONST_2': bool + [209; 216) 'CONST_2': isize + [226; 227) 'c': i32 + [230; 231) 'f': fn f(bool) -> i32 + [230; 239) 'f(z || y)': i32 + [230; 243) 'f(z || y) + 5': i32 + [232; 233) 'z': bool + [232; 238) 'z || y': bool + [237; 238) 'y': bool + [242; 243) '5': i32 + [253; 254) 'd': {unknown} + [257; 258) 'b': {unknown} + [268; 269) 'g': () + [272; 283) 'minus_forty': isize + [272; 288) 'minus_...y ^= i': () + [287; 288) 'i': isize + [298; 301) 'ten': usize + [311; 313) '10': usize + [323; 336) 'ten_is_eleven': bool + [339; 342) 'ten': usize + [339; 354) 'ten == some_num': bool + [346; 354) 'some_num': usize + [361; 364) 'ten': usize + [361; 368) 'ten < 3': bool + [367; 368) '3': usize + "### + ); +} + +#[test] +fn infer_field_autoderef() { + assert_snapshot!( + infer(r#" +struct A { + b: B, +} +struct B; + +fn test1(a: A) { + let a1 = a; + a1.b; + let a2 = &a; + a2.b; + let a3 = &mut a; + a3.b; + let a4 = &&&&&&&a; + a4.b; + let a5 = &mut &&mut &&mut a; + a5.b; +} + +fn test2(a1: *const A, a2: *mut A) { + a1.b; + a2.b; +} +"#), + @r###" + [44; 45) 'a': A + [50; 213) '{ ...5.b; }': () + [60; 62) 'a1': A + [65; 66) 'a': A + [72; 74) 'a1': A + [72; 76) 'a1.b': B + [86; 88) 'a2': &A + [91; 93) '&a': &A + [92; 93) 'a': A + [99; 101) 'a2': &A + [99; 103) 'a2.b': B + [113; 115) 'a3': &mut A + [118; 124) '&mut a': &mut A + [123; 124) 'a': A + [130; 132) 'a3': &mut A + [130; 134) 'a3.b': B + [144; 146) 'a4': &&&&&&&A + [149; 157) '&&&&&&&a': &&&&&&&A + [150; 157) '&&&&&&a': &&&&&&A + [151; 157) '&&&&&a': &&&&&A + [152; 157) '&&&&a': &&&&A + [153; 157) '&&&a': &&&A + [154; 157) '&&a': &&A + [155; 157) '&a': &A + [156; 157) 'a': A + [163; 165) 'a4': &&&&&&&A + [163; 167) 'a4.b': B + [177; 179) 'a5': &mut &&mut &&mut A + [182; 200) '&mut &...&mut a': &mut &&mut &&mut A + [187; 200) '&&mut &&mut a': &&mut &&mut A + [188; 200) '&mut &&mut a': &mut &&mut A + [193; 200) '&&mut a': &&mut A + [194; 200) '&mut a': &mut A + [199; 200) 'a': A + [206; 208) 'a5': &mut &&mut &&mut A + [206; 210) 'a5.b': B + [224; 226) 'a1': *const A + [238; 240) 'a2': *mut A + [250; 273) '{ ...2.b; }': () + [256; 258) 'a1': *const A + [256; 260) 'a1.b': B + [266; 268) 'a2': *mut A + [266; 270) 'a2.b': B + "### + ); +} + +#[test] +fn infer_argument_autoderef() { + assert_snapshot!( + infer(r#" +#[lang = "deref"] +pub trait Deref { + type Target; + fn deref(&self) -> &Self::Target; +} + +struct A(T); + +impl A { + fn foo(&self) -> &T { + &self.0 + } +} + +struct B(T); + +impl Deref for B { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn test() { + let t = A::foo(&&B(B(A(42)))); +} +"#), + @r###" + [68; 72) 'self': &Self + [139; 143) 'self': &A + [151; 174) '{ ... }': &T + [161; 168) '&self.0': &T + [162; 166) 'self': &A + [162; 168) 'self.0': T + [255; 259) 'self': &B + [278; 301) '{ ... }': &T + [288; 295) '&self.0': &T + [289; 293) 'self': &B + [289; 295) 'self.0': T + [315; 353) '{ ...))); }': () + [325; 326) 't': &i32 + [329; 335) 'A::foo': fn foo(&A) -> &T + [329; 350) 'A::foo...42))))': &i32 + [336; 349) '&&B(B(A(42)))': &&B>> + [337; 349) '&B(B(A(42)))': &B>> + [338; 339) 'B': B>>(T) -> B + [338; 349) 'B(B(A(42)))': B>> + [340; 341) 'B': B>(T) -> B + [340; 348) 'B(A(42))': B> + [342; 343) 'A': A(T) -> A + [342; 347) 'A(42)': A + [344; 346) '42': i32 + "### + ); +} + +#[test] +fn infer_method_argument_autoderef() { + assert_snapshot!( + infer(r#" +#[lang = "deref"] +pub trait Deref { + type Target; + fn deref(&self) -> &Self::Target; +} + +struct A(*mut T); + +impl A { + fn foo(&self, x: &A) -> &T { + &*x.0 + } +} + +struct B(T); + +impl Deref for B { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn test(a: A) { + let t = A(0 as *mut _).foo(&&B(B(a))); +} +"#), + @r###" + [68; 72) 'self': &Self + [144; 148) 'self': &A + [150; 151) 'x': &A + [166; 187) '{ ... }': &T + [176; 181) '&*x.0': &T + [177; 181) '*x.0': T + [178; 179) 'x': &A + [178; 181) 'x.0': *mut T + [268; 272) 'self': &B + [291; 314) '{ ... }': &T + [301; 308) '&self.0': &T + [302; 306) 'self': &B + [302; 308) 'self.0': T + [326; 327) 'a': A + [337; 383) '{ ...))); }': () + [347; 348) 't': &i32 + [351; 352) 'A': A(*mut T) -> A + [351; 365) 'A(0 as *mut _)': A + [351; 380) 'A(0 as...B(a)))': &i32 + [353; 354) '0': i32 + [353; 364) '0 as *mut _': *mut i32 + [370; 379) '&&B(B(a))': &&B>> + [371; 379) '&B(B(a))': &B>> + [372; 373) 'B': B>>(T) -> B + [372; 379) 'B(B(a))': B>> + [374; 375) 'B': B>(T) -> B + [374; 378) 'B(a)': B> + [376; 377) 'a': A + "### + ); +} + +#[test] +fn infer_in_elseif() { + assert_snapshot!( + infer(r#" +struct Foo { field: i32 } +fn main(foo: Foo) { + if true { + + } else if false { + foo.field + } +} +"#), + @r###" + [35; 38) 'foo': Foo + [45; 109) '{ ... } }': () + [51; 107) 'if tru... }': () + [54; 58) 'true': bool + [59; 67) '{ }': () + [73; 107) 'if fal... }': () + [76; 81) 'false': bool + [82; 107) '{ ... }': i32 + [92; 95) 'foo': Foo + [92; 101) 'foo.field': i32 + "### + ) +} + +#[test] +fn infer_if_match_with_return() { + assert_snapshot!( + infer(r#" +fn foo() { + let _x1 = if true { + 1 + } else { + return; + }; + let _x2 = if true { + 2 + } else { + return + }; + let _x3 = match true { + true => 3, + _ => { + return; + } + }; + let _x4 = match true { + true => 4, + _ => return + }; +}"#), + @r###" + [10; 323) '{ ... }; }': () + [20; 23) '_x1': i32 + [26; 80) 'if tru... }': i32 + [29; 33) 'true': bool + [34; 51) '{ ... }': i32 + [44; 45) '1': i32 + [57; 80) '{ ... }': ! + [67; 73) 'return': ! + [90; 93) '_x2': i32 + [96; 149) 'if tru... }': i32 + [99; 103) 'true': bool + [104; 121) '{ ... }': i32 + [114; 115) '2': i32 + [127; 149) '{ ... }': ! + [137; 143) 'return': ! + [159; 162) '_x3': i32 + [165; 247) 'match ... }': i32 + [171; 175) 'true': bool + [186; 190) 'true': bool + [194; 195) '3': i32 + [205; 206) '_': bool + [210; 241) '{ ... }': ! + [224; 230) 'return': ! + [257; 260) '_x4': i32 + [263; 320) 'match ... }': i32 + [269; 273) 'true': bool + [284; 288) 'true': bool + [292; 293) '4': i32 + [303; 304) '_': bool + [308; 314) 'return': ! + "### + ) +} + +#[test] +fn infer_inherent_method() { + assert_snapshot!( + infer(r#" +struct A; + +impl A { + fn foo(self, x: u32) -> i32 {} +} + +mod b { + impl super::A { + fn bar(&self, x: u64) -> i64 {} + } +} + +fn test(a: A) { + a.foo(1); + (&a).bar(1); + a.bar(1); +} +"#), + @r###" + [32; 36) 'self': A + [38; 39) 'x': u32 + [53; 55) '{}': () + [103; 107) 'self': &A + [109; 110) 'x': u64 + [124; 126) '{}': () + [144; 145) 'a': A + [150; 198) '{ ...(1); }': () + [156; 157) 'a': A + [156; 164) 'a.foo(1)': i32 + [162; 163) '1': u32 + [170; 181) '(&a).bar(1)': i64 + [171; 173) '&a': &A + [172; 173) 'a': A + [179; 180) '1': u64 + [187; 188) 'a': A + [187; 195) 'a.bar(1)': i64 + [193; 194) '1': u64 + "### + ); +} + +#[test] +fn infer_inherent_method_str() { + assert_snapshot!( + infer(r#" +#[lang = "str"] +impl str { + fn foo(&self) -> i32 {} +} + +fn test() { + "foo".foo(); +} +"#), + @r###" + [40; 44) 'self': &str + [53; 55) '{}': () + [69; 89) '{ ...o(); }': () + [75; 80) '"foo"': &str + [75; 86) '"foo".foo()': i32 + "### + ); +} + +#[test] +fn infer_tuple() { + assert_snapshot!( + infer(r#" +fn test(x: &str, y: isize) { + let a: (u32, &str) = (1, "a"); + let b = (a, x); + let c = (y, x); + let d = (c, x); + let e = (1, "e"); + let f = (e, "d"); +} +"#), + @r###" + [9; 10) 'x': &str + [18; 19) 'y': isize + [28; 170) '{ ...d"); }': () + [38; 39) 'a': (u32, &str) + [55; 63) '(1, "a")': (u32, &str) + [56; 57) '1': u32 + [59; 62) '"a"': &str + [73; 74) 'b': ((u32, &str), &str) + [77; 83) '(a, x)': ((u32, &str), &str) + [78; 79) 'a': (u32, &str) + [81; 82) 'x': &str + [93; 94) 'c': (isize, &str) + [97; 103) '(y, x)': (isize, &str) + [98; 99) 'y': isize + [101; 102) 'x': &str + [113; 114) 'd': ((isize, &str), &str) + [117; 123) '(c, x)': ((isize, &str), &str) + [118; 119) 'c': (isize, &str) + [121; 122) 'x': &str + [133; 134) 'e': (i32, &str) + [137; 145) '(1, "e")': (i32, &str) + [138; 139) '1': i32 + [141; 144) '"e"': &str + [155; 156) 'f': ((i32, &str), &str) + [159; 167) '(e, "d")': ((i32, &str), &str) + [160; 161) 'e': (i32, &str) + [163; 166) '"d"': &str + "### + ); +} + +#[test] +fn infer_array() { + assert_snapshot!( + infer(r#" +fn test(x: &str, y: isize) { + let a = [x]; + let b = [a, a]; + let c = [b, b]; + + let d = [y, 1, 2, 3]; + let d = [1, y, 2, 3]; + let e = [y]; + let f = [d, d]; + let g = [e, e]; + + let h = [1, 2]; + let i = ["a", "b"]; + + let b = [a, ["b"]]; + let x: [u8; 0] = []; +} +"#), + @r###" + [9; 10) 'x': &str + [18; 19) 'y': isize + [28; 293) '{ ... []; }': () + [38; 39) 'a': [&str;_] + [42; 45) '[x]': [&str;_] + [43; 44) 'x': &str + [55; 56) 'b': [[&str;_];_] + [59; 65) '[a, a]': [[&str;_];_] + [60; 61) 'a': [&str;_] + [63; 64) 'a': [&str;_] + [75; 76) 'c': [[[&str;_];_];_] + [79; 85) '[b, b]': [[[&str;_];_];_] + [80; 81) 'b': [[&str;_];_] + [83; 84) 'b': [[&str;_];_] + [96; 97) 'd': [isize;_] + [100; 112) '[y, 1, 2, 3]': [isize;_] + [101; 102) 'y': isize + [104; 105) '1': isize + [107; 108) '2': isize + [110; 111) '3': isize + [122; 123) 'd': [isize;_] + [126; 138) '[1, y, 2, 3]': [isize;_] + [127; 128) '1': isize + [130; 131) 'y': isize + [133; 134) '2': isize + [136; 137) '3': isize + [148; 149) 'e': [isize;_] + [152; 155) '[y]': [isize;_] + [153; 154) 'y': isize + [165; 166) 'f': [[isize;_];_] + [169; 175) '[d, d]': [[isize;_];_] + [170; 171) 'd': [isize;_] + [173; 174) 'd': [isize;_] + [185; 186) 'g': [[isize;_];_] + [189; 195) '[e, e]': [[isize;_];_] + [190; 191) 'e': [isize;_] + [193; 194) 'e': [isize;_] + [206; 207) 'h': [i32;_] + [210; 216) '[1, 2]': [i32;_] + [211; 212) '1': i32 + [214; 215) '2': i32 + [226; 227) 'i': [&str;_] + [230; 240) '["a", "b"]': [&str;_] + [231; 234) '"a"': &str + [236; 239) '"b"': &str + [251; 252) 'b': [[&str;_];_] + [255; 265) '[a, ["b"]]': [[&str;_];_] + [256; 257) 'a': [&str;_] + [259; 264) '["b"]': [&str;_] + [260; 263) '"b"': &str + [275; 276) 'x': [u8;_] + [288; 290) '[]': [u8;_] + "### + ); +} + +#[test] +fn infer_struct_generics() { + assert_snapshot!( + infer(r#" +struct A { + x: T, +} + +fn test(a1: A, i: i32) { + a1.x; + let a2 = A { x: i }; + a2.x; + let a3 = A:: { x: 1 }; + a3.x; +} +"#), + @r###" + [36; 38) 'a1': A + [48; 49) 'i': i32 + [56; 147) '{ ...3.x; }': () + [62; 64) 'a1': A + [62; 66) 'a1.x': u32 + [76; 78) 'a2': A + [81; 91) 'A { x: i }': A + [88; 89) 'i': i32 + [97; 99) 'a2': A + [97; 101) 'a2.x': i32 + [111; 113) 'a3': A + [116; 134) 'A:: + [131; 132) '1': i128 + [140; 142) 'a3': A + [140; 144) 'a3.x': i128 + "### + ); +} + +#[test] +fn infer_tuple_struct_generics() { + assert_snapshot!( + infer(r#" +struct A(T); +enum Option { Some(T), None } +use Option::*; + +fn test() { + A(42); + A(42u128); + Some("x"); + Option::Some("x"); + None; + let x: Option = None; +} +"#), + @r###" + [76; 184) '{ ...one; }': () + [82; 83) 'A': A(T) -> A + [82; 87) 'A(42)': A + [84; 86) '42': i32 + [93; 94) 'A': A(T) -> A + [93; 102) 'A(42u128)': A + [95; 101) '42u128': u128 + [108; 112) 'Some': Some<&str>(T) -> Option + [108; 117) 'Some("x")': Option<&str> + [113; 116) '"x"': &str + [123; 135) 'Option::Some': Some<&str>(T) -> Option + [123; 140) 'Option...e("x")': Option<&str> + [136; 139) '"x"': &str + [146; 150) 'None': Option<{unknown}> + [160; 161) 'x': Option + [177; 181) 'None': Option + "### + ); +} + +#[test] +fn infer_function_generics() { + assert_snapshot!( + infer(r#" +fn id(t: T) -> T { t } + +fn test() { + id(1u32); + id::(1); + let x: u64 = id(1); +} +"#), + @r###" + [10; 11) 't': T + [21; 26) '{ t }': T + [23; 24) 't': T + [38; 98) '{ ...(1); }': () + [44; 46) 'id': fn id(T) -> T + [44; 52) 'id(1u32)': u32 + [47; 51) '1u32': u32 + [58; 68) 'id::': fn id(T) -> T + [58; 71) 'id::(1)': i128 + [69; 70) '1': i128 + [81; 82) 'x': u64 + [90; 92) 'id': fn id(T) -> T + [90; 95) 'id(1)': u64 + [93; 94) '1': u64 + "### + ); +} + +#[test] +fn infer_impl_generics() { + assert_snapshot!( + infer(r#" +struct A { + x: T1, + y: T2, +} +impl A { + fn x(self) -> X { + self.x + } + fn y(self) -> Y { + self.y + } + fn z(self, t: T) -> (X, Y, T) { + (self.x, self.y, t) + } +} + +fn test() -> i128 { + let a = A { x: 1u64, y: 1i64 }; + a.x(); + a.y(); + a.z(1i128); + a.z::(1); +} +"#), + @r###" + [74; 78) 'self': A + [85; 107) '{ ... }': X + [95; 99) 'self': A + [95; 101) 'self.x': X + [117; 121) 'self': A + [128; 150) '{ ... }': Y + [138; 142) 'self': A + [138; 144) 'self.y': Y + [163; 167) 'self': A + [169; 170) 't': T + [188; 223) '{ ... }': (X, Y, T) + [198; 217) '(self.....y, t)': (X, Y, T) + [199; 203) 'self': A + [199; 205) 'self.x': X + [207; 211) 'self': A + [207; 213) 'self.y': Y + [215; 216) 't': T + [245; 342) '{ ...(1); }': () + [255; 256) 'a': A + [259; 281) 'A { x:...1i64 }': A + [266; 270) '1u64': u64 + [275; 279) '1i64': i64 + [287; 288) 'a': A + [287; 292) 'a.x()': u64 + [298; 299) 'a': A + [298; 303) 'a.y()': i64 + [309; 310) 'a': A + [309; 319) 'a.z(1i128)': (u64, i64, i128) + [313; 318) '1i128': i128 + [325; 326) 'a': A + [325; 339) 'a.z::(1)': (u64, i64, u128) + [337; 338) '1': u128 + "### + ); +} + +#[test] +fn infer_impl_generics_with_autoderef() { + assert_snapshot!( + infer(r#" +enum Option { + Some(T), + None, +} +impl Option { + fn as_ref(&self) -> Option<&T> {} +} +fn test(o: Option) { + (&o).as_ref(); + o.as_ref(); +} +"#), + @r###" + [78; 82) 'self': &Option + [98; 100) '{}': () + [111; 112) 'o': Option + [127; 165) '{ ...f(); }': () + [133; 146) '(&o).as_ref()': Option<&u32> + [134; 136) '&o': &Option + [135; 136) 'o': Option + [152; 153) 'o': Option + [152; 162) 'o.as_ref()': Option<&u32> + "### + ); +} + +#[test] +fn infer_generic_chain() { + assert_snapshot!( + infer(r#" +struct A { + x: T, +} +impl A { + fn x(self) -> T2 { + self.x + } +} +fn id(t: T) -> T { t } + +fn test() -> i128 { + let x = 1; + let y = id(x); + let a = A { x: id(y) }; + let z = id(a.x); + let b = A { x: z }; + b.x() +} +"#), + @r###" + [53; 57) 'self': A + [65; 87) '{ ... }': T2 + [75; 79) 'self': A + [75; 81) 'self.x': T2 + [99; 100) 't': T + [110; 115) '{ t }': T + [112; 113) 't': T + [135; 261) '{ ....x() }': i128 + [146; 147) 'x': i128 + [150; 151) '1': i128 + [162; 163) 'y': i128 + [166; 168) 'id': fn id(T) -> T + [166; 171) 'id(x)': i128 + [169; 170) 'x': i128 + [182; 183) 'a': A + [186; 200) 'A { x: id(y) }': A + [193; 195) 'id': fn id(T) -> T + [193; 198) 'id(y)': i128 + [196; 197) 'y': i128 + [211; 212) 'z': i128 + [215; 217) 'id': fn id(T) -> T + [215; 222) 'id(a.x)': i128 + [218; 219) 'a': A + [218; 221) 'a.x': i128 + [233; 234) 'b': A + [237; 247) 'A { x: z }': A + [244; 245) 'z': i128 + [254; 255) 'b': A + [254; 259) 'b.x()': i128 + "### + ); +} + +#[test] +fn infer_associated_const() { + assert_snapshot!( + infer(r#" +struct Struct; + +impl Struct { + const FOO: u32 = 1; +} + +enum Enum {} + +impl Enum { + const BAR: u32 = 2; +} + +trait Trait { + const ID: u32; +} + +struct TraitTest; + +impl Trait for TraitTest { + const ID: u32 = 5; +} + +fn test() { + let x = Struct::FOO; + let y = Enum::BAR; + let z = TraitTest::ID; +} +"#), + @r###" + [52; 53) '1': u32 + [105; 106) '2': u32 + [213; 214) '5': u32 + [229; 307) '{ ...:ID; }': () + [239; 240) 'x': u32 + [243; 254) 'Struct::FOO': u32 + [264; 265) 'y': u32 + [268; 277) 'Enum::BAR': u32 + [287; 288) 'z': u32 + [291; 304) 'TraitTest::ID': u32 + "### + ); +} + +#[test] +fn infer_type_alias() { + assert_snapshot!( + infer(r#" +struct A { x: X, y: Y } +type Foo = A; +type Bar = A; +type Baz = A; +fn test(x: Foo, y: Bar<&str>, z: Baz) { + x.x; + x.y; + y.x; + y.y; + z.x; + z.y; +} +"#), + @r###" + [116; 117) 'x': A + [124; 125) 'y': A<&str, u128> + [138; 139) 'z': A + [154; 211) '{ ...z.y; }': () + [160; 161) 'x': A + [160; 163) 'x.x': u32 + [169; 170) 'x': A + [169; 172) 'x.y': i128 + [178; 179) 'y': A<&str, u128> + [178; 181) 'y.x': &str + [187; 188) 'y': A<&str, u128> + [187; 190) 'y.y': u128 + [196; 197) 'z': A + [196; 199) 'z.x': u8 + [205; 206) 'z': A + [205; 208) 'z.y': i8 + "### + ) +} + +#[test] +fn recursive_type_alias() { + assert_snapshot!( + infer(r#" +struct A {} +type Foo = Foo; +type Bar = A; +fn test(x: Foo) {} +"#), + @r###" + [59; 60) 'x': {unknown} + [67; 69) '{}': () + "### + ) +} + +#[test] +fn infer_type_param() { + assert_snapshot!( + infer(r#" +fn id(x: T) -> T { + x +} + +fn clone(x: &T) -> T { + *x +} + +fn test() { + let y = 10u32; + id(y); + let x: bool = clone(z); + id::(1); +} +"#), + @r###" + [10; 11) 'x': T + [21; 30) '{ x }': T + [27; 28) 'x': T + [44; 45) 'x': &T + [56; 66) '{ *x }': T + [62; 64) '*x': T + [63; 64) 'x': &T + [78; 158) '{ ...(1); }': () + [88; 89) 'y': u32 + [92; 97) '10u32': u32 + [103; 105) 'id': fn id(T) -> T + [103; 108) 'id(y)': u32 + [106; 107) 'y': u32 + [118; 119) 'x': bool + [128; 133) 'clone': fn clone(&T) -> T + [128; 136) 'clone(z)': bool + [134; 135) 'z': &bool + [142; 152) 'id::': fn id(T) -> T + [142; 155) 'id::(1)': i128 + [153; 154) '1': i128 + "### + ); +} + +#[test] +fn infer_const() { + assert_snapshot!( + infer(r#" +struct Foo; +impl Foo { const ASSOC_CONST: u32 = 0; } +const GLOBAL_CONST: u32 = 101; +fn test() { + const LOCAL_CONST: u32 = 99; + let x = LOCAL_CONST; + let z = GLOBAL_CONST; + let id = Foo::ASSOC_CONST; +} +"#), + @r###" + [49; 50) '0': u32 + [80; 83) '101': u32 + [95; 213) '{ ...NST; }': () + [138; 139) 'x': {unknown} + [142; 153) 'LOCAL_CONST': {unknown} + [163; 164) 'z': u32 + [167; 179) 'GLOBAL_CONST': u32 + [189; 191) 'id': u32 + [194; 210) 'Foo::A..._CONST': u32 + "### + ); +} + +#[test] +fn infer_static() { + assert_snapshot!( + infer(r#" +static GLOBAL_STATIC: u32 = 101; +static mut GLOBAL_STATIC_MUT: u32 = 101; +fn test() { + static LOCAL_STATIC: u32 = 99; + static mut LOCAL_STATIC_MUT: u32 = 99; + let x = LOCAL_STATIC; + let y = LOCAL_STATIC_MUT; + let z = GLOBAL_STATIC; + let w = GLOBAL_STATIC_MUT; +} +"#), + @r###" + [29; 32) '101': u32 + [70; 73) '101': u32 + [85; 280) '{ ...MUT; }': () + [173; 174) 'x': {unknown} + [177; 189) 'LOCAL_STATIC': {unknown} + [199; 200) 'y': {unknown} + [203; 219) 'LOCAL_...IC_MUT': {unknown} + [229; 230) 'z': u32 + [233; 246) 'GLOBAL_STATIC': u32 + [256; 257) 'w': u32 + [260; 277) 'GLOBAL...IC_MUT': u32 + "### + ); +} + +#[test] +fn shadowing_primitive() { + let t = type_at( + r#" +//- /main.rs +struct i32; +struct Foo; + +impl i32 { fn foo(&self) -> Foo { Foo } } + +fn main() { + let x: i32 = i32; + x.foo()<|>; +}"#, + ); + assert_eq!(t, "Foo"); +} + +#[test] +fn not_shadowing_primitive_by_module() { + let t = type_at( + r#" +//- /str.rs +fn foo() {} + +//- /main.rs +mod str; +fn foo() -> &'static str { "" } + +fn main() { + foo()<|>; +}"#, + ); + assert_eq!(t, "&str"); +} + +#[test] +fn not_shadowing_module_by_primitive() { + let t = type_at( + r#" +//- /str.rs +fn foo() -> u32 {0} + +//- /main.rs +mod str; +fn foo() -> &'static str { "" } + +fn main() { + str::foo()<|>; +}"#, + ); + assert_eq!(t, "u32"); +} diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs new file mode 100644 index 000000000..93c5f9a15 --- /dev/null +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -0,0 +1,1424 @@ +use super::{infer, type_at, type_at_pos}; +use crate::test_db::TestDB; +use insta::assert_snapshot; +use ra_db::fixture::WithFixture; + +#[test] +fn infer_await() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std + +struct IntFuture; + +impl Future for IntFuture { + type Output = u64; +} + +fn test() { + let r = IntFuture; + let v = r.await; + v<|>; +} + +//- /std.rs crate:std +#[prelude_import] use future::*; +mod future { + trait Future { + type Output; + } +} + +"#, + ); + assert_eq!("u64", type_at_pos(&db, pos)); +} + +#[test] +fn infer_try() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std + +fn test() { + let r: Result = Result::Ok(1); + let v = r?; + v<|>; +} + +//- /std.rs crate:std + +#[prelude_import] use ops::*; +mod ops { + trait Try { + type Ok; + type Error; + } +} + +#[prelude_import] use result::*; +mod result { + enum Result { + Ok(O), + Err(E) + } + + impl crate::ops::Try for Result { + type Ok = O; + type Error = E; + } +} + +"#, + ); + assert_eq!("i32", type_at_pos(&db, pos)); +} + +#[test] +fn infer_for_loop() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std + +use std::collections::Vec; + +fn test() { + let v = Vec::new(); + v.push("foo"); + for x in v { + x<|>; + } +} + +//- /std.rs crate:std + +#[prelude_import] use iter::*; +mod iter { + trait IntoIterator { + type Item; + } +} + +mod collections { + struct Vec {} + impl Vec { + fn new() -> Self { Vec {} } + fn push(&mut self, t: T) { } + } + + impl crate::iter::IntoIterator for Vec { + type Item=T; + } +} +"#, + ); + assert_eq!("&str", type_at_pos(&db, pos)); +} + +#[test] +fn infer_from_bound_1() { + assert_snapshot!( + infer(r#" +trait Trait {} +struct S(T); +impl Trait for S {} +fn foo>(t: T) {} +fn test() { + let s = S(unknown); + foo(s); +} +"#), + @r###" + [86; 87) 't': T + [92; 94) '{}': () + [105; 144) '{ ...(s); }': () + [115; 116) 's': S + [119; 120) 'S': S(T) -> S + [119; 129) 'S(unknown)': S + [121; 128) 'unknown': u32 + [135; 138) 'foo': fn foo>(T) -> () + [135; 141) 'foo(s)': () + [139; 140) 's': S + "### + ); +} + +#[test] +fn infer_from_bound_2() { + assert_snapshot!( + infer(r#" +trait Trait {} +struct S(T); +impl Trait for S {} +fn foo>(t: T) -> U {} +fn test() { + let s = S(unknown); + let x: u32 = foo(s); +} +"#), + @r###" + [87; 88) 't': T + [98; 100) '{}': () + [111; 163) '{ ...(s); }': () + [121; 122) 's': S + [125; 126) 'S': S(T) -> S + [125; 135) 'S(unknown)': S + [127; 134) 'unknown': u32 + [145; 146) 'x': u32 + [154; 157) 'foo': fn foo>(T) -> U + [154; 160) 'foo(s)': u32 + [158; 159) 's': S + "### + ); +} + +#[test] +fn infer_project_associated_type() { + // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234 + assert_snapshot!( + infer(r#" +trait Iterable { + type Item; +} +struct S; +impl Iterable for S { type Item = u32; } +fn test() { + let x: ::Item = 1; + let y: ::Item = no_matter; + let z: T::Item = no_matter; + let a: ::Item = no_matter; +} +"#), + @r###" + [108; 261) '{ ...ter; }': () + [118; 119) 'x': u32 + [145; 146) '1': u32 + [156; 157) 'y': {unknown} + [183; 192) 'no_matter': {unknown} + [202; 203) 'z': {unknown} + [215; 224) 'no_matter': {unknown} + [234; 235) 'a': {unknown} + [249; 258) 'no_matter': {unknown} + "### + ); +} + +#[test] +fn infer_return_associated_type() { + assert_snapshot!( + infer(r#" +trait Iterable { + type Item; +} +struct S; +impl Iterable for S { type Item = u32; } +fn foo1(t: T) -> T::Item {} +fn foo2(t: T) -> ::Item {} +fn foo3(t: T) -> ::Item {} +fn test() { + let x = foo1(S); + let y = foo2(S); + let z = foo3(S); +} +"#), + @r###" + [106; 107) 't': T + [123; 125) '{}': () + [147; 148) 't': T + [178; 180) '{}': () + [202; 203) 't': T + [221; 223) '{}': () + [234; 300) '{ ...(S); }': () + [244; 245) 'x': u32 + [248; 252) 'foo1': fn foo1(T) -> ::Item + [248; 255) 'foo1(S)': u32 + [253; 254) 'S': S + [265; 266) 'y': u32 + [269; 273) 'foo2': fn foo2(T) -> ::Item + [269; 276) 'foo2(S)': u32 + [274; 275) 'S': S + [286; 287) 'z': u32 + [290; 294) 'foo3': fn foo3(T) -> ::Item + [290; 297) 'foo3(S)': u32 + [295; 296) 'S': S + "### + ); +} + +#[test] +fn infer_associated_type_bound() { + assert_snapshot!( + infer(r#" +trait Iterable { + type Item; +} +fn test>() { + let y: T::Item = unknown; +} +"#), + @r###" + [67; 100) '{ ...own; }': () + [77; 78) 'y': {unknown} + [90; 97) 'unknown': {unknown} + "### + ); +} + +#[test] +fn infer_const_body() { + assert_snapshot!( + infer(r#" +const A: u32 = 1 + 1; +static B: u64 = { let x = 1; x }; +"#), + @r###" + [16; 17) '1': u32 + [16; 21) '1 + 1': u32 + [20; 21) '1': u32 + [39; 55) '{ let ...1; x }': u64 + [45; 46) 'x': u64 + [49; 50) '1': u64 + [52; 53) 'x': u64 + "### + ); +} + +#[test] +fn tuple_struct_fields() { + assert_snapshot!( + infer(r#" +struct S(i32, u64); +fn test() -> u64 { + let a = S(4, 6); + let b = a.0; + a.1 +} +"#), + @r###" + [38; 87) '{ ... a.1 }': u64 + [48; 49) 'a': S + [52; 53) 'S': S(i32, u64) -> S + [52; 59) 'S(4, 6)': S + [54; 55) '4': i32 + [57; 58) '6': u64 + [69; 70) 'b': i32 + [73; 74) 'a': S + [73; 76) 'a.0': i32 + [82; 83) 'a': S + [82; 85) 'a.1': u64 + "### + ); +} + +#[test] +fn tuple_struct_with_fn() { + assert_snapshot!( + infer(r#" +struct S(fn(u32) -> u64); +fn test() -> u64 { + let a = S(|i| 2*i); + let b = a.0(4); + a.0(2) +} +"#), + @r###" + [44; 102) '{ ...0(2) }': u64 + [54; 55) 'a': S + [58; 59) 'S': S(fn(u32) -> u64) -> S + [58; 68) 'S(|i| 2*i)': S + [60; 67) '|i| 2*i': |i32| -> i32 + [61; 62) 'i': i32 + [64; 65) '2': i32 + [64; 67) '2*i': i32 + [66; 67) 'i': i32 + [78; 79) 'b': u64 + [82; 83) 'a': S + [82; 85) 'a.0': fn(u32) -> u64 + [82; 88) 'a.0(4)': u64 + [86; 87) '4': u32 + [94; 95) 'a': S + [94; 97) 'a.0': fn(u32) -> u64 + [94; 100) 'a.0(2)': u64 + [98; 99) '2': u32 + "### + ); +} + +#[test] +fn indexing_arrays() { + assert_snapshot!( + infer("fn main() { &mut [9][2]; }"), + @r###" + [10; 26) '{ &mut...[2]; }': () + [12; 23) '&mut [9][2]': &mut {unknown} + [17; 20) '[9]': [i32;_] + [17; 23) '[9][2]': {unknown} + [18; 19) '9': i32 + [21; 22) '2': i32 + "### + ) +} + +#[test] +fn deref_trait() { + let t = type_at( + r#" +//- /main.rs +#[lang = "deref"] +trait Deref { + type Target; + fn deref(&self) -> &Self::Target; +} + +struct Arc; +impl Deref for Arc { + type Target = T; +} + +struct S; +impl S { + fn foo(&self) -> u128 {} +} + +fn test(s: Arc) { + (*s, s.foo())<|>; +} +"#, + ); + assert_eq!(t, "(S, u128)"); +} + +#[test] +fn deref_trait_with_inference_var() { + let t = type_at( + r#" +//- /main.rs +#[lang = "deref"] +trait Deref { + type Target; + fn deref(&self) -> &Self::Target; +} + +struct Arc; +fn new_arc() -> Arc {} +impl Deref for Arc { + type Target = T; +} + +struct S; +fn foo(a: Arc) {} + +fn test() { + let a = new_arc(); + let b = (*a)<|>; + foo(a); +} +"#, + ); + assert_eq!(t, "S"); +} + +#[test] +fn deref_trait_infinite_recursion() { + let t = type_at( + r#" +//- /main.rs +#[lang = "deref"] +trait Deref { + type Target; + fn deref(&self) -> &Self::Target; +} + +struct S; + +impl Deref for S { + type Target = S; +} + +fn test(s: S) { + s.foo()<|>; +} +"#, + ); + assert_eq!(t, "{unknown}"); +} + +#[test] +fn deref_trait_with_question_mark_size() { + let t = type_at( + r#" +//- /main.rs +#[lang = "deref"] +trait Deref { + type Target; + fn deref(&self) -> &Self::Target; +} + +struct Arc; +impl Deref for Arc { + type Target = T; +} + +struct S; +impl S { + fn foo(&self) -> u128 {} +} + +fn test(s: Arc) { + (*s, s.foo())<|>; +} +"#, + ); + assert_eq!(t, "(S, u128)"); +} + +#[test] +fn obligation_from_function_clause() { + let t = type_at( + r#" +//- /main.rs +struct S; + +trait Trait {} +impl Trait for S {} + +fn foo, U>(t: T) -> U {} + +fn test(s: S) { + foo(s)<|>; +} +"#, + ); + assert_eq!(t, "u32"); +} + +#[test] +fn obligation_from_method_clause() { + let t = type_at( + r#" +//- /main.rs +struct S; + +trait Trait {} +impl Trait for S {} + +struct O; +impl O { + fn foo, U>(&self, t: T) -> U {} +} + +fn test() { + O.foo(S)<|>; +} +"#, + ); + assert_eq!(t, "isize"); +} + +#[test] +fn obligation_from_self_method_clause() { + let t = type_at( + r#" +//- /main.rs +struct S; + +trait Trait {} +impl Trait for S {} + +impl S { + fn foo(&self) -> U where Self: Trait {} +} + +fn test() { + S.foo()<|>; +} +"#, + ); + assert_eq!(t, "i64"); +} + +#[test] +fn obligation_from_impl_clause() { + let t = type_at( + r#" +//- /main.rs +struct S; + +trait Trait {} +impl Trait<&str> for S {} + +struct O; +impl> O { + fn foo(&self) -> U {} +} + +fn test(o: O) { + o.foo()<|>; +} +"#, + ); + assert_eq!(t, "&str"); +} + +#[test] +fn generic_param_env_1() { + let t = type_at( + r#" +//- /main.rs +trait Clone {} +trait Trait { fn foo(self) -> u128; } +struct S; +impl Clone for S {} +impl Trait for T where T: Clone {} +fn test(t: T) { t.foo()<|>; } +"#, + ); + assert_eq!(t, "u128"); +} + +#[test] +fn generic_param_env_1_not_met() { + let t = type_at( + r#" +//- /main.rs +trait Clone {} +trait Trait { fn foo(self) -> u128; } +struct S; +impl Clone for S {} +impl Trait for T where T: Clone {} +fn test(t: T) { t.foo()<|>; } +"#, + ); + assert_eq!(t, "{unknown}"); +} + +#[test] +fn generic_param_env_2() { + let t = type_at( + r#" +//- /main.rs +trait Trait { fn foo(self) -> u128; } +struct S; +impl Trait for S {} +fn test(t: T) { t.foo()<|>; } +"#, + ); + assert_eq!(t, "u128"); +} + +#[test] +fn generic_param_env_2_not_met() { + let t = type_at( + r#" +//- /main.rs +trait Trait { fn foo(self) -> u128; } +struct S; +impl Trait for S {} +fn test(t: T) { t.foo()<|>; } +"#, + ); + assert_eq!(t, "{unknown}"); +} + +#[test] +fn generic_param_env_deref() { + let t = type_at( + r#" +//- /main.rs +#[lang = "deref"] +trait Deref { + type Target; +} +trait Trait {} +impl Deref for T where T: Trait { + type Target = i128; +} +fn test(t: T) { (*t)<|>; } +"#, + ); + assert_eq!(t, "i128"); +} + +#[test] +fn associated_type_placeholder() { + let t = type_at( + r#" +//- /main.rs +pub trait ApplyL { + type Out; +} + +pub struct RefMutL; + +impl ApplyL for RefMutL { + type Out = ::Out; +} + +fn test() { + let y: as ApplyL>::Out = no_matter; + y<|>; +} +"#, + ); + // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. + // FIXME: fix type parameter names going missing when going through Chalk + assert_eq!(t, "ApplyL::Out<[missing name]>"); +} + +#[test] +fn associated_type_placeholder_2() { + let t = type_at( + r#" +//- /main.rs +pub trait ApplyL { + type Out; +} +fn foo(t: T) -> ::Out; + +fn test(t: T) { + let y = foo(t); + y<|>; +} +"#, + ); + // FIXME here Chalk doesn't normalize the type to a placeholder. I think we + // need to add a rule like Normalize(::Out -> ApplyL::Out) + // to the trait env ourselves here; probably Chalk can't do this by itself. + // assert_eq!(t, "ApplyL::Out<[missing name]>"); + assert_eq!(t, "{unknown}"); +} + +#[test] +fn impl_trait() { + assert_snapshot!( + infer(r#" +trait Trait { + fn foo(&self) -> T; + fn foo2(&self) -> i64; +} +fn bar() -> impl Trait {} + +fn test(x: impl Trait, y: &impl Trait) { + x; + y; + let z = bar(); + x.foo(); + y.foo(); + z.foo(); + x.foo2(); + y.foo2(); + z.foo2(); +} +"#), + @r###" + [30; 34) 'self': &Self + [55; 59) 'self': &Self + [99; 101) '{}': () + [111; 112) 'x': impl Trait + [131; 132) 'y': &impl Trait + [152; 269) '{ ...2(); }': () + [158; 159) 'x': impl Trait + [165; 166) 'y': &impl Trait + [176; 177) 'z': impl Trait + [180; 183) 'bar': fn bar() -> impl Trait + [180; 185) 'bar()': impl Trait + [191; 192) 'x': impl Trait + [191; 198) 'x.foo()': u64 + [204; 205) 'y': &impl Trait + [204; 211) 'y.foo()': u64 + [217; 218) 'z': impl Trait + [217; 224) 'z.foo()': u64 + [230; 231) 'x': impl Trait + [230; 238) 'x.foo2()': i64 + [244; 245) 'y': &impl Trait + [244; 252) 'y.foo2()': i64 + [258; 259) 'z': impl Trait + [258; 266) 'z.foo2()': i64 + "### + ); +} + +#[test] +fn dyn_trait() { + assert_snapshot!( + infer(r#" +trait Trait { + fn foo(&self) -> T; + fn foo2(&self) -> i64; +} +fn bar() -> dyn Trait {} + +fn test(x: dyn Trait, y: &dyn Trait) { + x; + y; + let z = bar(); + x.foo(); + y.foo(); + z.foo(); + x.foo2(); + y.foo2(); + z.foo2(); +} +"#), + @r###" + [30; 34) 'self': &Self + [55; 59) 'self': &Self + [98; 100) '{}': () + [110; 111) 'x': dyn Trait + [129; 130) 'y': &dyn Trait + [149; 266) '{ ...2(); }': () + [155; 156) 'x': dyn Trait + [162; 163) 'y': &dyn Trait + [173; 174) 'z': dyn Trait + [177; 180) 'bar': fn bar() -> dyn Trait + [177; 182) 'bar()': dyn Trait + [188; 189) 'x': dyn Trait + [188; 195) 'x.foo()': u64 + [201; 202) 'y': &dyn Trait + [201; 208) 'y.foo()': u64 + [214; 215) 'z': dyn Trait + [214; 221) 'z.foo()': u64 + [227; 228) 'x': dyn Trait + [227; 235) 'x.foo2()': i64 + [241; 242) 'y': &dyn Trait + [241; 249) 'y.foo2()': i64 + [255; 256) 'z': dyn Trait + [255; 263) 'z.foo2()': i64 + "### + ); +} + +#[test] +fn dyn_trait_bare() { + assert_snapshot!( + infer(r#" +trait Trait { + fn foo(&self) -> u64; +} +fn bar() -> Trait {} + +fn test(x: Trait, y: &Trait) -> u64 { + x; + y; + let z = bar(); + x.foo(); + y.foo(); + z.foo(); +} +"#), + @r###" + [27; 31) 'self': &Self + [61; 63) '{}': () + [73; 74) 'x': dyn Trait + [83; 84) 'y': &dyn Trait + [101; 176) '{ ...o(); }': () + [107; 108) 'x': dyn Trait + [114; 115) 'y': &dyn Trait + [125; 126) 'z': dyn Trait + [129; 132) 'bar': fn bar() -> dyn Trait + [129; 134) 'bar()': dyn Trait + [140; 141) 'x': dyn Trait + [140; 147) 'x.foo()': u64 + [153; 154) 'y': &dyn Trait + [153; 160) 'y.foo()': u64 + [166; 167) 'z': dyn Trait + [166; 173) 'z.foo()': u64 + "### + ); +} + +#[test] +fn weird_bounds() { + assert_snapshot!( + infer(r#" +trait Trait {} +fn test() { + let a: impl Trait + 'lifetime = foo; + let b: impl 'lifetime = foo; + let b: impl (Trait) = foo; + let b: impl ('lifetime) = foo; + let d: impl ?Sized = foo; + let e: impl Trait + ?Sized = foo; +} +"#), + @r###" + [26; 237) '{ ...foo; }': () + [36; 37) 'a': impl Trait + {error} + [64; 67) 'foo': impl Trait + {error} + [77; 78) 'b': impl {error} + [97; 100) 'foo': impl {error} + [110; 111) 'b': impl Trait + [128; 131) 'foo': impl Trait + [141; 142) 'b': impl {error} + [163; 166) 'foo': impl {error} + [176; 177) 'd': impl {error} + [193; 196) 'foo': impl {error} + [206; 207) 'e': impl Trait + {error} + [231; 234) 'foo': impl Trait + {error} + "### + ); +} + +#[test] +fn assoc_type_bindings() { + assert_snapshot!( + infer(r#" +trait Trait { + type Type; +} + +fn get(t: T) -> ::Type {} +fn get2>(t: T) -> U {} +fn set>(t: T) -> T {t} + +struct S; +impl Trait for S { type Type = T; } + +fn test>(x: T, y: impl Trait) { + get(x); + get2(x); + get(y); + get2(y); + get(set(S)); + get2(set(S)); + get2(S::); +} +"#), + @r###" + [50; 51) 't': T + [78; 80) '{}': () + [112; 113) 't': T + [123; 125) '{}': () + [155; 156) 't': T + [166; 169) '{t}': T + [167; 168) 't': T + [257; 258) 'x': T + [263; 264) 'y': impl Trait + [290; 398) '{ ...r>); }': () + [296; 299) 'get': fn get(T) -> ::Type + [296; 302) 'get(x)': {unknown} + [300; 301) 'x': T + [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U + [308; 315) 'get2(x)': {unknown} + [313; 314) 'x': T + [321; 324) 'get': fn get>(T) -> ::Type + [321; 327) 'get(y)': {unknown} + [325; 326) 'y': impl Trait + [333; 337) 'get2': fn get2<{unknown}, impl Trait>(T) -> U + [333; 340) 'get2(y)': {unknown} + [338; 339) 'y': impl Trait + [346; 349) 'get': fn get>(T) -> ::Type + [346; 357) 'get(set(S))': u64 + [350; 353) 'set': fn set>(T) -> T + [350; 356) 'set(S)': S + [354; 355) 'S': S + [363; 367) 'get2': fn get2>(T) -> U + [363; 375) 'get2(set(S))': u64 + [368; 371) 'set': fn set>(T) -> T + [368; 374) 'set(S)': S + [372; 373) 'S': S + [381; 385) 'get2': fn get2>(T) -> U + [381; 395) 'get2(S::)': str + [386; 394) 'S::': S + "### + ); +} + +#[test] +fn impl_trait_assoc_binding_projection_bug() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std +pub trait Language { + type Kind; +} +pub enum RustLanguage {} +impl Language for RustLanguage { + type Kind = SyntaxKind; +} +struct SyntaxNode {} +fn foo() -> impl Iterator> {} + +trait Clone { + fn clone(&self) -> Self; +} + +fn api_walkthrough() { + for node in foo() { + node.clone()<|>; + } +} + +//- /std.rs crate:std +#[prelude_import] use iter::*; +mod iter { + trait IntoIterator { + type Item; + } + trait Iterator { + type Item; + } + impl IntoIterator for T { + type Item = ::Item; + } +} +"#, + ); + assert_eq!("{unknown}", type_at_pos(&db, pos)); +} + +#[test] +fn projection_eq_within_chalk() { + // std::env::set_var("CHALK_DEBUG", "1"); + assert_snapshot!( + infer(r#" +trait Trait1 { + type Type; +} +trait Trait2 { + fn foo(self) -> T; +} +impl Trait2 for U where U: Trait1 {} + +fn test>(x: T) { + x.foo(); +} +"#), + @r###" + [62; 66) 'self': Self + [164; 165) 'x': T + [170; 186) '{ ...o(); }': () + [176; 177) 'x': T + [176; 183) 'x.foo()': {unknown} + "### + ); +} + +#[test] +fn where_clause_trait_in_scope_for_method_resolution() { + let t = type_at( + r#" +//- /main.rs +mod foo { + trait Trait { + fn foo(&self) -> u32 {} + } +} + +fn test(x: T) { + x.foo()<|>; +} +"#, + ); + assert_eq!(t, "u32"); +} + +#[test] +fn super_trait_method_resolution() { + assert_snapshot!( + infer(r#" +mod foo { + trait SuperTrait { + fn foo(&self) -> u32 {} + } +} +trait Trait1: foo::SuperTrait {} +trait Trait2 where Self: foo::SuperTrait {} + +fn test(x: T, y: U) { + x.foo(); + y.foo(); +} +"#), + @r###" + [50; 54) 'self': &Self + [63; 65) '{}': () + [182; 183) 'x': T + [188; 189) 'y': U + [194; 223) '{ ...o(); }': () + [200; 201) 'x': T + [200; 207) 'x.foo()': u32 + [213; 214) 'y': U + [213; 220) 'y.foo()': u32 + "### + ); +} + +#[test] +fn super_trait_cycle() { + // This just needs to not crash + assert_snapshot!( + infer(r#" +trait A: B {} +trait B: A {} + +fn test(x: T) { + x.foo(); +} +"#), + @r###" + [44; 45) 'x': T + [50; 66) '{ ...o(); }': () + [56; 57) 'x': T + [56; 63) 'x.foo()': {unknown} + "### + ); +} + +#[test] +fn super_trait_assoc_type_bounds() { + assert_snapshot!( + infer(r#" +trait SuperTrait { type Type; } +trait Trait where Self: SuperTrait {} + +fn get2>(t: T) -> U {} +fn set>(t: T) -> T {t} + +struct S; +impl SuperTrait for S { type Type = T; } +impl Trait for S {} + +fn test() { + get2(set(S)); +} +"#), + @r###" + [103; 104) 't': T + [114; 116) '{}': () + [146; 147) 't': T + [157; 160) '{t}': T + [158; 159) 't': T + [259; 280) '{ ...S)); }': () + [265; 269) 'get2': fn get2>(T) -> U + [265; 277) 'get2(set(S))': u64 + [270; 273) 'set': fn set>(T) -> T + [270; 276) 'set(S)': S + [274; 275) 'S': S + "### + ); +} + +#[test] +fn fn_trait() { + assert_snapshot!( + infer(r#" +trait FnOnce { + type Output; + + fn call_once(self, args: Args) -> >::Output; +} + +fn test u128>(f: F) { + f.call_once((1, 2)); +} +"#), + @r###" + [57; 61) 'self': Self + [63; 67) 'args': Args + [150; 151) 'f': F + [156; 184) '{ ...2)); }': () + [162; 163) 'f': F + [162; 181) 'f.call...1, 2))': {unknown} + [174; 180) '(1, 2)': (u32, u64) + [175; 176) '1': u32 + [178; 179) '2': u64 + "### + ); +} + +#[test] +fn closure_1() { + assert_snapshot!( + infer(r#" +#[lang = "fn_once"] +trait FnOnce { + type Output; +} + +enum Option { Some(T), None } +impl Option { + fn map U>(self, f: F) -> Option {} +} + +fn test() { + let x = Option::Some(1u32); + x.map(|v| v + 1); + x.map(|_v| 1u64); + let y: Option = x.map(|_v| 1); +} +"#), + @r###" + [148; 152) 'self': Option + [154; 155) 'f': F + [173; 175) '{}': () + [189; 308) '{ ... 1); }': () + [199; 200) 'x': Option + [203; 215) 'Option::Some': Some(T) -> Option + [203; 221) 'Option...(1u32)': Option + [216; 220) '1u32': u32 + [227; 228) 'x': Option + [227; 243) 'x.map(...v + 1)': Option + [233; 242) '|v| v + 1': |u32| -> u32 + [234; 235) 'v': u32 + [237; 238) 'v': u32 + [237; 242) 'v + 1': u32 + [241; 242) '1': u32 + [249; 250) 'x': Option + [249; 265) 'x.map(... 1u64)': Option + [255; 264) '|_v| 1u64': |u32| -> u64 + [256; 258) '_v': u32 + [260; 264) '1u64': u64 + [275; 276) 'y': Option + [292; 293) 'x': Option + [292; 305) 'x.map(|_v| 1)': Option + [298; 304) '|_v| 1': |u32| -> i64 + [299; 301) '_v': u32 + [303; 304) '1': i64 + "### + ); +} + +#[test] +fn closure_2() { + assert_snapshot!( + infer(r#" +trait FnOnce { + type Output; +} + +fn test u64>(f: F) { + f(1); + let g = |v| v + 1; + g(1u64); + let h = |v| 1u128 + v; +} +"#), + @r###" + [73; 74) 'f': F + [79; 155) '{ ...+ v; }': () + [85; 86) 'f': F + [85; 89) 'f(1)': {unknown} + [87; 88) '1': i32 + [99; 100) 'g': |u64| -> i32 + [103; 112) '|v| v + 1': |u64| -> i32 + [104; 105) 'v': u64 + [107; 108) 'v': u64 + [107; 112) 'v + 1': i32 + [111; 112) '1': i32 + [118; 119) 'g': |u64| -> i32 + [118; 125) 'g(1u64)': i32 + [120; 124) '1u64': u64 + [135; 136) 'h': |u128| -> u128 + [139; 152) '|v| 1u128 + v': |u128| -> u128 + [140; 141) 'v': u128 + [143; 148) '1u128': u128 + [143; 152) '1u128 + v': u128 + [151; 152) 'v': u128 + "### + ); +} + +#[test] +fn closure_as_argument_inference_order() { + assert_snapshot!( + infer(r#" +#[lang = "fn_once"] +trait FnOnce { + type Output; +} + +fn foo1 U>(x: T, f: F) -> U {} +fn foo2 U>(f: F, x: T) -> U {} + +struct S; +impl S { + fn method(self) -> u64; + + fn foo1 U>(self, x: T, f: F) -> U {} + fn foo2 U>(self, f: F, x: T) -> U {} +} + +fn test() { + let x1 = foo1(S, |s| s.method()); + let x2 = foo2(|s| s.method(), S); + let x3 = S.foo1(S, |s| s.method()); + let x4 = S.foo2(|s| s.method(), S); +} +"#), + @r###" + [95; 96) 'x': T + [101; 102) 'f': F + [112; 114) '{}': () + [148; 149) 'f': F + [154; 155) 'x': T + [165; 167) '{}': () + [202; 206) 'self': S + [254; 258) 'self': S + [260; 261) 'x': T + [266; 267) 'f': F + [277; 279) '{}': () + [317; 321) 'self': S + [323; 324) 'f': F + [329; 330) 'x': T + [340; 342) '{}': () + [356; 515) '{ ... S); }': () + [366; 368) 'x1': u64 + [371; 375) 'foo1': fn foo1 u64>(T, F) -> U + [371; 394) 'foo1(S...hod())': u64 + [376; 377) 'S': S + [379; 393) '|s| s.method()': |S| -> u64 + [380; 381) 's': S + [383; 384) 's': S + [383; 393) 's.method()': u64 + [404; 406) 'x2': u64 + [409; 413) 'foo2': fn foo2 u64>(F, T) -> U + [409; 432) 'foo2(|...(), S)': u64 + [414; 428) '|s| s.method()': |S| -> u64 + [415; 416) 's': S + [418; 419) 's': S + [418; 428) 's.method()': u64 + [430; 431) 'S': S + [442; 444) 'x3': u64 + [447; 448) 'S': S + [447; 472) 'S.foo1...hod())': u64 + [454; 455) 'S': S + [457; 471) '|s| s.method()': |S| -> u64 + [458; 459) 's': S + [461; 462) 's': S + [461; 471) 's.method()': u64 + [482; 484) 'x4': u64 + [487; 488) 'S': S + [487; 512) 'S.foo2...(), S)': u64 + [494; 508) '|s| s.method()': |S| -> u64 + [495; 496) 's': S + [498; 499) 's': S + [498; 508) 's.method()': u64 + [510; 511) 'S': S + "### + ); +} + +#[test] +fn unselected_projection_in_trait_env_1() { + let t = type_at( + r#" +//- /main.rs +trait Trait { + type Item; +} + +trait Trait2 { + fn foo(&self) -> u32; +} + +fn test() where T::Item: Trait2 { + let x: T::Item = no_matter; + x.foo()<|>; +} +"#, + ); + assert_eq!(t, "u32"); +} + +#[test] +fn unselected_projection_in_trait_env_2() { + let t = type_at( + r#" +//- /main.rs +trait Trait { + type Item; +} + +trait Trait2 { + fn foo(&self) -> u32; +} + +fn test() where T::Item: Trait2, T: Trait, U: Trait<()> { + let x: T::Item = no_matter; + x.foo()<|>; +} +"#, + ); + assert_eq!(t, "u32"); +} + +#[test] +fn trait_impl_self_ty() { + let t = type_at( + r#" +//- /main.rs +trait Trait { + fn foo(&self); +} + +struct S; + +impl Trait for S {} + +fn test() { + S.foo()<|>; +} +"#, + ); + assert_eq!(t, "()"); +} + +#[test] +fn trait_impl_self_ty_cycle() { + let t = type_at( + r#" +//- /main.rs +trait Trait { + fn foo(&self); +} + +struct S; + +impl Trait for S {} + +fn test() { + S.foo()<|>; +} +"#, + ); + assert_eq!(t, "{unknown}"); +} + +#[test] +fn unselected_projection_in_trait_env_cycle_1() { + let t = type_at( + r#" +//- /main.rs +trait Trait { + type Item; +} + +trait Trait2 {} + +fn test() where T: Trait2 { + let x: T::Item = no_matter<|>; +} +"#, + ); + // this is a legitimate cycle + assert_eq!(t, "{unknown}"); +} + +#[test] +fn unselected_projection_in_trait_env_cycle_2() { + let t = type_at( + r#" +//- /main.rs +trait Trait { + type Item; +} + +fn test() where T: Trait, U: Trait { + let x: T::Item = no_matter<|>; +} +"#, + ); + // this is a legitimate cycle + assert_eq!(t, "{unknown}"); +} -- cgit v1.2.3 From 7cbedc50bcf048c87f141a85418581076d67fc7a Mon Sep 17 00:00:00 2001 From: ice1000 Date: Tue, 3 Dec 2019 15:23:21 -0500 Subject: Fix test compilation --- crates/ra_hir_ty/src/test_db.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index 1dc9793f9..476f6df52 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs @@ -74,7 +74,7 @@ impl TestDB { for &krate in self.relevant_crates(file_id).iter() { let crate_def_map = self.crate_def_map(krate); for (local_id, data) in crate_def_map.modules.iter() { - if data.definition == Some(file_id) { + if data.origin.file_id() == Some(file_id) { return ModuleId { krate, local_id }; } } -- cgit v1.2.3 From db8a00bd99cdc10ae8166fca3827eefebf791471 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Thu, 5 Dec 2019 19:29:57 +0100 Subject: Implement derive(Copy, Clone) properly (well, kind of) --- crates/ra_hir_ty/src/tests/macros.rs | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 0d9a35ce0..9c29a054e 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -266,3 +266,54 @@ fn main() { "### ); } + +#[test] +fn infer_derive_clone_simple() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std +#[derive(Clone)] +struct S; +fn test() { + S.clone()<|>; +} + +//- /lib.rs crate:std +#[prelude_import] +use clone::*; +mod clone { + trait Clone { + fn clone(&self) -> Self; + } +} +"#, + ); + assert_eq!("S", type_at_pos(&db, pos)); +} + +#[test] +fn infer_derive_clone_with_params() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std +#[derive(Clone)] +struct S; +#[derive(Clone)] +struct Wrapper(T); +struct NonClone; +fn test() { + (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; +} + +//- /lib.rs crate:std +#[prelude_import] +use clone::*; +mod clone { + trait Clone { + fn clone(&self) -> Self; + } +} +"#, + ); + assert_eq!("(Wrapper, {unknown})", type_at_pos(&db, pos)); +} -- cgit v1.2.3 From b84ce79f911014dfed6bc9d31d6699bc123d3561 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 5 Dec 2019 21:17:17 +0100 Subject: Simplify test --- crates/ra_hir_ty/src/tests.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index c520bb375..9f373a8f4 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -11,8 +11,8 @@ use std::fmt::Write; use std::sync::Arc; use hir_def::{ - body::BodySourceMap, db::DefDatabase, nameres::CrateDefMap, AssocItemId, DefWithBodyId, - LocalModuleId, Lookup, ModuleDefId, + body::BodySourceMap, child_from_source::ChildFromSource, db::DefDatabase, nameres::CrateDefMap, + AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, }; use hir_expand::InFile; use insta::assert_snapshot; @@ -31,18 +31,15 @@ use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResu fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { let file = db.parse(pos.file_id).ok().unwrap(); let expr = algo::find_node_at_offset::(file.syntax(), pos.offset).unwrap(); - + let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); let module = db.module_for_file(pos.file_id); - let crate_def_map = db.crate_def_map(module.krate); - for decl in crate_def_map[module.local_id].scope.declarations() { - if let ModuleDefId::FunctionId(func) = decl { - let (_body, source_map) = db.body_with_source_map(func.into()); - if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { - let infer = db.infer(func.into()); - let ty = &infer[expr_id]; - return ty.display(db).to_string(); - } - } + let func = module.child_from_source(db, InFile::new(pos.file_id.into(), fn_def)).unwrap(); + + let (_body, source_map) = db.body_with_source_map(func.into()); + if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { + let infer = db.infer(func.into()); + let ty = &infer[expr_id]; + return ty.display(db).to_string(); } panic!("Can't find expression") } -- cgit v1.2.3 From f86fe3d891ab295e9e394a1338da86524a6205d3 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Thu, 5 Dec 2019 23:02:31 +0100 Subject: Don't unify within a reference If we are expecting a `&Foo` and get a `&something`, when checking the `something`, we are *expecting* a `Foo`, but we shouldn't try to unify whatever we get with that expectation, because it could actually be a `&Foo`, and `&&Foo` coerces to `&Foo`. So this fixes quite a few false type mismatches. --- crates/ra_hir_ty/src/infer/expr.rs | 21 ++++++++++---------- crates/ra_hir_ty/src/tests.rs | 26 ++++++++++++++++++++++++ crates/ra_hir_ty/src/tests/coercion.rs | 36 ++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 11 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 1e78f6efd..b8df27706 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -201,7 +201,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } Expr::Return { expr } => { if let Some(expr) = expr { - self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone())); + self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone())); } Ty::simple(TypeCtor::Never) } @@ -245,7 +245,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ty } Expr::Field { expr, name } => { - let receiver_ty = self.infer_expr(*expr, &Expectation::none()); + let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none()); let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); let ty = autoderef::autoderef( self.db, @@ -280,7 +280,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.normalize_associated_types_in(ty) } Expr::Await { expr } => { - let inner_ty = self.infer_expr(*expr, &Expectation::none()); + let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); let ty = match self.resolve_future_future_output() { Some(future_future_output_alias) => { let ty = self.table.new_type_var(); @@ -299,7 +299,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ty } Expr::Try { expr } => { - let inner_ty = self.infer_expr(*expr, &Expectation::none()); + let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); let ty = match self.resolve_ops_try_ok() { Some(ops_try_ok_alias) => { let ty = self.table.new_type_var(); @@ -318,7 +318,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ty } Expr::Cast { expr, type_ref } => { - let _inner_ty = self.infer_expr(*expr, &Expectation::none()); + let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); let cast_ty = self.make_ty(type_ref); // FIXME check the cast... cast_ty @@ -334,12 +334,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } else { Expectation::none() }; - // FIXME reference coercions etc. - let inner_ty = self.infer_expr(*expr, &expectation); + let inner_ty = self.infer_expr_inner(*expr, &expectation); Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) } Expr::Box { expr } => { - let inner_ty = self.infer_expr(*expr, &Expectation::none()); + let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); if let Some(box_) = self.resolve_boxed_box() { Ty::apply_one(TypeCtor::Adt(box_), inner_ty) } else { @@ -347,7 +346,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } Expr::UnaryOp { expr, op } => { - let inner_ty = self.infer_expr(*expr, &Expectation::none()); + let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); match op { UnaryOp::Deref => match self.resolver.krate() { Some(krate) => { @@ -417,7 +416,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { _ => Ty::Unknown, }, Expr::Range { lhs, rhs, range_type } => { - let lhs_ty = lhs.map(|e| self.infer_expr(e, &Expectation::none())); + let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none())); let rhs_expect = lhs_ty .as_ref() .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone())); @@ -455,7 +454,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } Expr::Index { base, index } => { - let _base_ty = self.infer_expr(*base, &Expectation::none()); + let _base_ty = self.infer_expr_inner(*base, &Expectation::none()); let _index_ty = self.infer_expr(*index, &Expectation::none()); // FIXME: use `std::ops::Index::Output` to figure out the real return type Ty::Unknown diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 9f373a8f4..f1b67555f 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -50,6 +50,10 @@ fn type_at(content: &str) -> String { } fn infer(content: &str) -> String { + infer_with_mismatches(content, false) +} + +fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let (db, file_id) = TestDB::with_single_file(content); let mut acc = String::new(); @@ -57,6 +61,7 @@ fn infer(content: &str) -> String { let mut infer_def = |inference_result: Arc, body_source_map: Arc| { let mut types = Vec::new(); + let mut mismatches = Vec::new(); for (pat, ty) in inference_result.type_of_pat.iter() { let syntax_ptr = match body_source_map.pat_syntax(pat) { @@ -76,6 +81,9 @@ fn infer(content: &str) -> String { None => continue, }; types.push((syntax_ptr, ty)); + if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { + mismatches.push((syntax_ptr, mismatch)); + } } // sort ranges for consistency @@ -101,6 +109,24 @@ fn infer(content: &str) -> String { ) .unwrap(); } + if include_mismatches { + mismatches.sort_by_key(|(src_ptr, _)| { + (src_ptr.value.range().start(), src_ptr.value.range().end()) + }); + for (src_ptr, mismatch) in &mismatches { + let range = src_ptr.value.range(); + let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" }; + write!( + acc, + "{}{}: expected {}, got {}\n", + macro_prefix, + range, + mismatch.expected.display(&db), + mismatch.actual.display(&db), + ) + .unwrap(); + } + } }; let module = db.module_for_file(file_id); diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 1530fcc63..58b22396f 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -1,3 +1,4 @@ +use super::infer_with_mismatches; use insta::assert_snapshot; use test_utils::covers; @@ -367,3 +368,38 @@ fn test() { "### ); } + +#[test] +fn coerce_autoderef() { + assert_snapshot!( + infer_with_mismatches(r#" +struct Foo; +fn takes_ref_foo(x: &Foo) {} +fn test() { + takes_ref_foo(&Foo); + takes_ref_foo(&&Foo); + takes_ref_foo(&&&Foo); +} +"#, true), + @r###" + [30; 31) 'x': &Foo + [39; 41) '{}': () + [52; 133) '{ ...oo); }': () + [58; 71) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> () + [58; 77) 'takes_...(&Foo)': () + [72; 76) '&Foo': &Foo + [73; 76) 'Foo': Foo + [83; 96) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> () + [83; 103) 'takes_...&&Foo)': () + [97; 102) '&&Foo': &&Foo + [98; 102) '&Foo': &Foo + [99; 102) 'Foo': Foo + [109; 122) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> () + [109; 130) 'takes_...&&Foo)': () + [123; 129) '&&&Foo': &&&Foo + [124; 129) '&&Foo': &&Foo + [125; 129) '&Foo': &Foo + [126; 129) 'Foo': Foo + "### + ); +} -- cgit v1.2.3 From 76ff5b7c15b2c4e85895a49e5859e546d1d6227e Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 3 Dec 2019 19:33:48 +0800 Subject: Add tests --- crates/ra_hir_ty/src/tests/macros.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 9c29a054e..812f171db 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -210,6 +210,35 @@ pub fn baz() -> usize { 31usize } assert_eq!("(i32, usize)", type_at_pos(&db, pos)); } +#[test] +fn infer_type_value_non_legacy_macro_use_as() { + assert_snapshot!( + infer(r#" +mod m { + macro_rules! _foo { + ($x:ident) => { type $x = u64; } + } + pub(crate) use _foo as foo; +} + +m::foo!(foo); +use foo as bar; +fn f() -> bar { 0 } +fn main() { + let _a = f(); +} +"#), + @r###" + [159; 164) '{ 0 }': u64 + [161; 162) '0': u64 + [175; 199) '{ ...f(); }': () + [187; 189) '_a': u64 + [193; 194) 'f': fn f() -> u64 + [193; 196) 'f()': u64 + "### + ); +} + #[test] fn infer_builtin_macros_line() { assert_snapshot!( -- cgit v1.2.3 From 8c86963d47953045f2f33ee6620d305a6589641e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 5 Dec 2019 23:34:12 +0100 Subject: DynMap This might, or might not help us to reduce boilerplate associated with plumbing values from analysis to the IDE layer --- crates/ra_hir_ty/src/tests.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 9f373a8f4..6920ac747 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -11,8 +11,8 @@ use std::fmt::Write; use std::sync::Arc; use hir_def::{ - body::BodySourceMap, child_from_source::ChildFromSource, db::DefDatabase, nameres::CrateDefMap, - AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, + body::BodySourceMap, child_by_source::ChildBySource, db::DefDatabase, keys, + nameres::CrateDefMap, AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, }; use hir_expand::InFile; use insta::assert_snapshot; @@ -33,7 +33,9 @@ fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { let expr = algo::find_node_at_offset::(file.syntax(), pos.offset).unwrap(); let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); let module = db.module_for_file(pos.file_id); - let func = module.child_from_source(db, InFile::new(pos.file_id.into(), fn_def)).unwrap(); + let func = *module.child_by_source(db)[keys::FUNCTION] + .get(&InFile::new(pos.file_id.into(), fn_def)) + .unwrap(); let (_body, source_map) = db.body_with_source_map(func.into()); if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { -- cgit v1.2.3 From 30fefcc08cc0c670ce541476491238d258ca55c1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 6 Dec 2019 17:35:05 +0100 Subject: Store GenericParams in arena --- crates/ra_hir_ty/src/infer/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index b8df27706..0c3428999 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -662,7 +662,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let mut substs = Vec::with_capacity(parent_param_count + param_count); // Parent arguments are unknown, except for the receiver type if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { - for param in &parent_generics.params { + for (_id, param) in parent_generics.params.iter() { if param.name == name::SELF_TYPE { substs.push(receiver_ty.clone()); } else { -- cgit v1.2.3 From 8e9837df21942ca12a5aece0a868ea46eb405742 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 7 Dec 2019 11:50:36 +0100 Subject: Remove idx and parent generics from generics This makes `hir_def::GenericParams` flatter. The logic for re-numbering the params is moved to hir instead. --- crates/ra_hir_ty/src/autoderef.rs | 8 ++-- crates/ra_hir_ty/src/infer/expr.rs | 24 ++++++----- crates/ra_hir_ty/src/lib.rs | 32 +++++--------- crates/ra_hir_ty/src/lower.rs | 35 ++++++++------- crates/ra_hir_ty/src/traits/chalk.rs | 14 +++--- crates/ra_hir_ty/src/utils.rs | 82 +++++++++++++++++++++++++++++++++++- 6 files changed, 135 insertions(+), 60 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs index 9d1d4e48c..a6db7f623 100644 --- a/crates/ra_hir_ty/src/autoderef.rs +++ b/crates/ra_hir_ty/src/autoderef.rs @@ -10,10 +10,10 @@ use hir_expand::name; use log::{info, warn}; use ra_db::CrateId; -use crate::db::HirDatabase; - -use super::{ +use crate::{ + db::HirDatabase, traits::{InEnvironment, Solution}, + utils::generics, Canonical, Substs, Ty, TypeWalk, }; @@ -54,7 +54,7 @@ fn deref_by_trait( }; let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?; - let generic_params = db.generic_params(target.into()); + let generic_params = generics(db, target.into()); if generic_params.count_params_including_parent() != 1 { // the Target type + Deref trait should only have one generic parameter, // namely Deref's Self type diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 0c3428999..e52040eb5 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -6,7 +6,6 @@ use std::sync::Arc; use hir_def::{ builtin_type::Signedness, expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, - generics::GenericParams, path::{GenericArg, GenericArgs}, resolver::resolver_for_expr, AdtId, ContainerId, Lookup, StructFieldId, @@ -15,7 +14,11 @@ use hir_expand::name::{self, Name}; use ra_syntax::ast::RangeOp; use crate::{ - autoderef, db::HirDatabase, method_resolution, op, traits::InEnvironment, utils::variant_data, + autoderef, + db::HirDatabase, + method_resolution, op, + traits::InEnvironment, + utils::{generics, variant_data, Generics}, CallableDef, InferTy, IntTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, }; @@ -596,7 +599,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Some((ty, func)) => { let ty = canonicalized_receiver.decanonicalize_ty(ty); self.write_method_resolution(tgt_expr, func); - (ty, self.db.value_ty(func.into()), Some(self.db.generic_params(func.into()))) + (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into()))) } None => (receiver_ty, Ty::Unknown, None), }; @@ -653,16 +656,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn substs_for_method_call( &mut self, - def_generics: Option>, + def_generics: Option, generic_args: Option<&GenericArgs>, receiver_ty: &Ty, ) -> Substs { - let (parent_param_count, param_count) = - def_generics.as_ref().map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); + let (parent_param_count, param_count) = def_generics + .as_ref() + .map_or((0, 0), |g| (g.count_parent_params(), g.params.params.len())); let mut substs = Vec::with_capacity(parent_param_count + param_count); // Parent arguments are unknown, except for the receiver type - if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { - for (_id, param) in parent_generics.params.iter() { + if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { + for (_id, param) in parent_generics { if param.name == name::SELF_TYPE { substs.push(receiver_ty.clone()); } else { @@ -706,9 +710,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { if let ContainerId::TraitId(trait_) = f.lookup(self.db).container { // construct a TraitDef let substs = a_ty.parameters.prefix( - self.db - .generic_params(trait_.into()) - .count_params_including_parent(), + generics(self.db, trait_.into()).count_params_including_parent(), ); self.obligations.push(Obligation::Trait(TraitRef { trait_: trait_.into(), diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 3c1f738df..99fd7158e 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -44,7 +44,7 @@ use std::sync::Arc; use std::{fmt, iter, mem}; use hir_def::{ - expr::ExprId, generics::GenericParams, type_ref::Mutability, AdtId, ContainerId, DefWithBodyId, + expr::ExprId, type_ref::Mutability, AdtId, ContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, }; use hir_expand::name::Name; @@ -53,7 +53,7 @@ use ra_db::{impl_intern_key, salsa, CrateId}; use crate::{ db::HirDatabase, primitive::{FloatTy, IntTy, Uncertain}, - utils::make_mut_slice, + utils::{generics, make_mut_slice, Generics}, }; use display::{HirDisplay, HirFormatter}; @@ -166,15 +166,15 @@ impl TypeCtor { | TypeCtor::Closure { .. } // 1 param representing the signature of the closure => 1, TypeCtor::Adt(adt) => { - let generic_params = db.generic_params(AdtId::from(adt).into()); + let generic_params = generics(db, AdtId::from(adt).into()); generic_params.count_params_including_parent() } TypeCtor::FnDef(callable) => { - let generic_params = db.generic_params(callable.into()); + let generic_params = generics(db, callable.into()); generic_params.count_params_including_parent() } TypeCtor::AssociatedType(type_alias) => { - let generic_params = db.generic_params(type_alias.into()); + let generic_params = generics(db, type_alias.into()); generic_params.count_params_including_parent() } TypeCtor::FnPtr { num_args } => num_args as usize + 1, @@ -364,35 +364,25 @@ impl Substs { } /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). - pub fn identity(generic_params: &GenericParams) -> Substs { + pub(crate) fn identity(generic_params: &Generics) -> Substs { Substs( - generic_params - .params_including_parent() - .into_iter() - .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() }) - .collect(), + generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone() }).collect(), ) } /// Return Substs that replace each parameter by a bound variable. - pub fn bound_vars(generic_params: &GenericParams) -> Substs { - Substs( - generic_params - .params_including_parent() - .into_iter() - .map(|p| Ty::Bound(p.idx)) - .collect(), - ) + pub(crate) fn bound_vars(generic_params: &Generics) -> Substs { + Substs(generic_params.iter().map(|(idx, _p)| Ty::Bound(idx)).collect()) } pub fn build_for_def(db: &impl HirDatabase, def: impl Into) -> SubstsBuilder { let def = def.into(); - let params = db.generic_params(def); + let params = generics(db, def); let param_count = params.count_params_including_parent(); Substs::builder(param_count) } - pub fn build_for_generics(generic_params: &GenericParams) -> SubstsBuilder { + pub(crate) fn build_for_generics(generic_params: &Generics) -> SubstsBuilder { Substs::builder(generic_params.count_params_including_parent()) } diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 32569ac66..d31f6a2d2 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -24,7 +24,7 @@ use crate::{ db::HirDatabase, primitive::{FloatTy, IntTy}, utils::{ - all_super_traits, associated_type_by_name_including_super_traits, make_mut_slice, + all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice, variant_data, }, FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, @@ -111,7 +111,9 @@ impl Ty { Some((it, None)) => it, _ => return None, }; - if let TypeNs::GenericParam(idx) = resolution { + if let TypeNs::GenericParam(param_id) = resolution { + let generics = generics(db, resolver.generic_def().expect("generics in scope")); + let idx = generics.param_idx(param_id); Some(idx) } else { None @@ -174,9 +176,11 @@ impl Ty { Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) }; } - TypeNs::GenericParam(idx) => { + TypeNs::GenericParam(param_id) => { + let generics = generics(db, resolver.generic_def().expect("generics in scope")); + let idx = generics.param_idx(param_id); // FIXME: maybe return name in resolution? - let name = resolved_segment.name.clone(); + let name = generics.param_name(param_id); Ty::Param { idx, name } } TypeNs::SelfType(impl_id) => db.impl_self_ty(impl_id).clone(), @@ -315,10 +319,10 @@ pub(super) fn substs_from_path_segment( add_self_param: bool, ) -> Substs { let mut substs = Vec::new(); - let def_generics = def_generic.map(|def| db.generic_params(def.into())); + let def_generics = def_generic.map(|def| generics(db, def.into())); let (parent_param_count, param_count) = - def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); + def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.params.len())); substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); if add_self_param { // FIXME this add_self_param argument is kind of a hack: Traits have the @@ -567,12 +571,11 @@ pub(crate) fn generic_predicates_query( /// Resolve the default type params from generics pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs { let resolver = def.resolver(db); - let generic_params = db.generic_params(def.into()); + let generic_params = generics(db, def.into()); let defaults = generic_params - .params_including_parent() - .into_iter() - .map(|p| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(db, &resolver, t))) + .iter() + .map(|(_idx, p)| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(db, &resolver, t))) .collect(); Substs(defaults) @@ -589,7 +592,7 @@ fn fn_sig_for_fn(db: &impl HirDatabase, def: FunctionId) -> FnSig { /// Build the declared type of a function. This should not need to look at the /// function body. fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty { - let generics = db.generic_params(def.into()); + let generics = generics(db, def.into()); let substs = Substs::identity(&generics); Ty::apply(TypeCtor::FnDef(def.into()), substs) } @@ -639,7 +642,7 @@ fn type_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> Ty { if struct_data.variant_data.is_unit() { return type_for_adt(db, def.into()); // Unit struct } - let generics = db.generic_params(def.into()); + let generics = generics(db, def.into()); let substs = Substs::identity(&generics); Ty::apply(TypeCtor::FnDef(def.into()), substs) } @@ -653,7 +656,7 @@ fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId .iter() .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) .collect::>(); - let generics = db.generic_params(def.parent.into()); + let generics = generics(db, def.parent.into()); let substs = Substs::identity(&generics); let ret = type_for_adt(db, def.parent.into()).subst(&substs); FnSig::from_params_and_return(params, ret) @@ -666,18 +669,18 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId) if var_data.is_unit() { return type_for_adt(db, def.parent.into()); // Unit variant } - let generics = db.generic_params(def.parent.into()); + let generics = generics(db, def.parent.into()); let substs = Substs::identity(&generics); Ty::apply(TypeCtor::FnDef(EnumVariantId::from(def).into()), substs) } fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty { - let generics = db.generic_params(adt.into()); + let generics = generics(db, adt.into()); Ty::apply(TypeCtor::Adt(adt), Substs::identity(&generics)) } fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty { - let generics = db.generic_params(t.into()); + let generics = generics(db, t.into()); let resolver = t.resolver(db); let type_ref = &db.type_alias_data(t).type_ref; let substs = Substs::identity(&generics); diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index e3f02fa15..1d44320b9 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -19,8 +19,8 @@ use ra_db::{ use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; use crate::{ - db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ProjectionTy, Substs, - TraitRef, Ty, TypeCtor, TypeWalk, + db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate, + ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }; /// This represents a trait whose name we could not resolve. @@ -547,7 +547,7 @@ pub(crate) fn associated_ty_data_query( ContainerId::TraitId(t) => t, _ => panic!("associated type not in trait"), }; - let generic_params = db.generic_params(type_alias.into()); + let generic_params = generics(db, type_alias.into()); let bound_data = chalk_rust_ir::AssociatedTyDatumBound { // FIXME add bounds and where clauses bounds: vec![], @@ -589,7 +589,7 @@ pub(crate) fn trait_datum_query( let trait_: TraitId = from_chalk(db, trait_id); let trait_data = db.trait_data(trait_); debug!("trait {:?} = {:?}", trait_id, trait_data.name); - let generic_params = db.generic_params(trait_.into()); + let generic_params = generics(db, trait_.into()); let bound_vars = Substs::bound_vars(&generic_params); let flags = chalk_rust_ir::TraitFlags { auto: trait_data.auto, @@ -626,7 +626,7 @@ pub(crate) fn struct_datum_query( let where_clauses = type_ctor .as_generic_def() .map(|generic_def| { - let generic_params = db.generic_params(generic_def.into()); + let generic_params = generics(db, generic_def.into()); let bound_vars = Substs::bound_vars(&generic_params); convert_where_clauses(db, generic_def, &bound_vars) }) @@ -669,7 +669,7 @@ fn impl_block_datum( let trait_ref = db.impl_trait(impl_id)?; let impl_data = db.impl_data(impl_id); - let generic_params = db.generic_params(impl_id.into()); + let generic_params = generics(db, impl_id.into()); let bound_vars = Substs::bound_vars(&generic_params); let trait_ref = trait_ref.subst(&bound_vars); let trait_ = trait_ref.trait_; @@ -767,7 +767,7 @@ fn type_alias_associated_ty_value( .trait_data(trait_ref.trait_) .associated_type_by_name(&type_alias_data.name) .expect("assoc ty value should not exist"); // validated when building the impl data as well - let generic_params = db.generic_params(impl_id.into()); + let generic_params = generics(db, impl_id.into()); let bound_vars = Substs::bound_vars(&generic_params); let ty = db.ty(type_alias.into()).subst(&bound_vars); let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) }; diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index e4ba890ef..2c458867f 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -5,9 +5,10 @@ use std::sync::Arc; use hir_def::{ adt::VariantData, db::DefDatabase, + generics::{GenericParamData, GenericParams}, resolver::{HasResolver, TypeNs}, type_ref::TypeRef, - TraitId, TypeAliasId, VariantId, + ContainerId, GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId, VariantId, }; use hir_expand::name::{self, Name}; @@ -82,3 +83,82 @@ pub(crate) fn make_mut_slice(a: &mut Arc<[T]>) -> &mut [T] { } Arc::get_mut(a).unwrap() } + +pub(crate) fn generics(db: &impl DefDatabase, def: GenericDefId) -> Generics { + let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); + Generics { def, params: db.generic_params(def), parent_generics } +} + +pub(crate) struct Generics { + def: GenericDefId, + pub(crate) params: Arc, + parent_generics: Option>, +} + +impl Generics { + pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { + self.parent_generics + .as_ref() + .into_iter() + .flat_map(|it| it.params.params.iter()) + .chain(self.params.params.iter()) + .enumerate() + .map(|(i, (_local_id, p))| (i as u32, p)) + } + + pub(crate) fn iter_parent<'a>( + &'a self, + ) -> impl Iterator + 'a { + self.parent_generics + .as_ref() + .into_iter() + .flat_map(|it| it.params.params.iter()) + .enumerate() + .map(|(i, (_local_id, p))| (i as u32, p)) + } + + pub(crate) fn count_parent_params(&self) -> usize { + self.parent_generics.as_ref().map_or(0, |p| p.count_params_including_parent()) + } + + pub(crate) fn count_params_including_parent(&self) -> usize { + let parent_count = self.count_parent_params(); + parent_count + self.params.params.len() + } + pub(crate) fn param_idx(&self, param: GenericParamId) -> u32 { + self.find_param(param).0 + } + pub(crate) fn param_name(&self, param: GenericParamId) -> Name { + self.find_param(param).1.name.clone() + } + fn find_param(&self, param: GenericParamId) -> (u32, &GenericParamData) { + if param.parent == self.def { + let (idx, (_local_id, data)) = self + .params + .params + .iter() + .enumerate() + .find(|(_, (idx, _))| *idx == param.local_id) + .unwrap(); + + return ((self.count_parent_params() + idx) as u32, data); + } + self.parent_generics.as_ref().unwrap().find_param(param) + } +} + +fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option { + let container = match def { + GenericDefId::FunctionId(it) => it.lookup(db).container, + GenericDefId::TypeAliasId(it) => it.lookup(db).container, + GenericDefId::ConstId(it) => it.lookup(db).container, + GenericDefId::EnumVariantId(it) => return Some(it.parent.into()), + GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None, + }; + + match container { + ContainerId::ImplId(it) => Some(it.into()), + ContainerId::TraitId(it) => Some(it.into()), + ContainerId::ModuleId(_) => None, + } +} -- cgit v1.2.3 From d6c2b92409902d9ceca8cd064026cfcc1f357cf6 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 7 Dec 2019 13:05:05 +0100 Subject: Refactor parameter count tracking --- crates/ra_hir_ty/src/autoderef.rs | 2 +- crates/ra_hir_ty/src/infer/expr.rs | 18 ++++++++---------- crates/ra_hir_ty/src/lib.rs | 10 +++++----- crates/ra_hir_ty/src/lower.rs | 13 ++++++------- crates/ra_hir_ty/src/traits/chalk.rs | 2 +- crates/ra_hir_ty/src/utils.rs | 17 +++++++++-------- 6 files changed, 30 insertions(+), 32 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs index a6db7f623..d557962b4 100644 --- a/crates/ra_hir_ty/src/autoderef.rs +++ b/crates/ra_hir_ty/src/autoderef.rs @@ -55,7 +55,7 @@ fn deref_by_trait( let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?; let generic_params = generics(db, target.into()); - if generic_params.count_params_including_parent() != 1 { + if generic_params.len() != 1 { // the Target type + Deref trait should only have one generic parameter, // namely Deref's Self type return None; diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index e52040eb5..2c296987c 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -660,10 +660,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { generic_args: Option<&GenericArgs>, receiver_ty: &Ty, ) -> Substs { - let (parent_param_count, param_count) = def_generics - .as_ref() - .map_or((0, 0), |g| (g.count_parent_params(), g.params.params.len())); - let mut substs = Vec::with_capacity(parent_param_count + param_count); + let (total_len, _parent_len, child_len) = + def_generics.as_ref().map_or((0, 0, 0), |g| g.len_split()); + let mut substs = Vec::with_capacity(total_len); // Parent arguments are unknown, except for the receiver type if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { for (_id, param) in parent_generics { @@ -677,7 +676,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // handle provided type arguments if let Some(generic_args) = generic_args { // if args are provided, it should be all of them, but we can't rely on that - for arg in generic_args.args.iter().take(param_count) { + for arg in generic_args.args.iter().take(child_len) { match arg { GenericArg::Type(type_ref) => { let ty = self.make_ty(type_ref); @@ -687,10 +686,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } }; let supplied_params = substs.len(); - for _ in supplied_params..parent_param_count + param_count { + for _ in supplied_params..total_len { substs.push(Ty::Unknown); } - assert_eq!(substs.len(), parent_param_count + param_count); + assert_eq!(substs.len(), total_len); Substs(substs.into()) } @@ -709,9 +708,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { CallableDef::FunctionId(f) => { if let ContainerId::TraitId(trait_) = f.lookup(self.db).container { // construct a TraitDef - let substs = a_ty.parameters.prefix( - generics(self.db, trait_.into()).count_params_including_parent(), - ); + let substs = + a_ty.parameters.prefix(generics(self.db, trait_.into()).len()); self.obligations.push(Obligation::Trait(TraitRef { trait_: trait_.into(), substs, diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 99fd7158e..036d3a589 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -167,15 +167,15 @@ impl TypeCtor { => 1, TypeCtor::Adt(adt) => { let generic_params = generics(db, AdtId::from(adt).into()); - generic_params.count_params_including_parent() + generic_params.len() } TypeCtor::FnDef(callable) => { let generic_params = generics(db, callable.into()); - generic_params.count_params_including_parent() + generic_params.len() } TypeCtor::AssociatedType(type_alias) => { let generic_params = generics(db, type_alias.into()); - generic_params.count_params_including_parent() + generic_params.len() } TypeCtor::FnPtr { num_args } => num_args as usize + 1, TypeCtor::Tuple { cardinality } => cardinality as usize, @@ -378,12 +378,12 @@ impl Substs { pub fn build_for_def(db: &impl HirDatabase, def: impl Into) -> SubstsBuilder { let def = def.into(); let params = generics(db, def); - let param_count = params.count_params_including_parent(); + let param_count = params.len(); Substs::builder(param_count) } pub(crate) fn build_for_generics(generic_params: &Generics) -> SubstsBuilder { - Substs::builder(generic_params.count_params_including_parent()) + Substs::builder(generic_params.len()) } pub fn build_for_type_ctor(db: &impl HirDatabase, type_ctor: TypeCtor) -> SubstsBuilder { diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index d31f6a2d2..eab91229e 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -321,9 +321,8 @@ pub(super) fn substs_from_path_segment( let mut substs = Vec::new(); let def_generics = def_generic.map(|def| generics(db, def.into())); - let (parent_param_count, param_count) = - def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.params.len())); - substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); + let (total_len, parent_len, child_len) = def_generics.map_or((0, 0, 0), |g| g.len_split()); + substs.extend(iter::repeat(Ty::Unknown).take(parent_len)); if add_self_param { // FIXME this add_self_param argument is kind of a hack: Traits have the // Self type as an implicit first type parameter, but it can't be @@ -334,8 +333,8 @@ pub(super) fn substs_from_path_segment( if let Some(generic_args) = &segment.args_and_bindings { // if args are provided, it should be all of them, but we can't rely on that let self_param_correction = if add_self_param { 1 } else { 0 }; - let param_count = param_count - self_param_correction; - for arg in generic_args.args.iter().take(param_count) { + let child_len = child_len + self_param_correction; + for arg in generic_args.args.iter().take(child_len) { match arg { GenericArg::Type(type_ref) => { let ty = Ty::from_hir(db, resolver, type_ref); @@ -346,10 +345,10 @@ pub(super) fn substs_from_path_segment( } // add placeholders for args that were not provided let supplied_params = substs.len(); - for _ in supplied_params..parent_param_count + param_count { + for _ in supplied_params..total_len { substs.push(Ty::Unknown); } - assert_eq!(substs.len(), parent_param_count + param_count); + assert_eq!(substs.len(), total_len); // handle defaults if let Some(def_generic) = def_generic { diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 1d44320b9..1e7ff93d5 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -557,7 +557,7 @@ pub(crate) fn associated_ty_data_query( trait_id: trait_.to_chalk(db), id, name: lalrpop_intern::intern(&db.type_alias_data(type_alias).name.to_string()), - binders: make_binders(bound_data, generic_params.count_params_including_parent()), + binders: make_binders(bound_data, generic_params.len()), }; Arc::new(datum) } diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 2c458867f..936cfe25e 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -117,13 +117,14 @@ impl Generics { .map(|(i, (_local_id, p))| (i as u32, p)) } - pub(crate) fn count_parent_params(&self) -> usize { - self.parent_generics.as_ref().map_or(0, |p| p.count_params_including_parent()) + pub(crate) fn len(&self) -> usize { + self.len_split().0 } - - pub(crate) fn count_params_including_parent(&self) -> usize { - let parent_count = self.count_parent_params(); - parent_count + self.params.params.len() + /// (total, parents, child) + pub(crate) fn len_split(&self) -> (usize, usize, usize) { + let parent = self.parent_generics.as_ref().map_or(0, |p| p.len()); + let child = self.params.params.len(); + (parent + child, parent, child) } pub(crate) fn param_idx(&self, param: GenericParamId) -> u32 { self.find_param(param).0 @@ -140,8 +141,8 @@ impl Generics { .enumerate() .find(|(_, (idx, _))| *idx == param.local_id) .unwrap(); - - return ((self.count_parent_params() + idx) as u32, data); + let (_total, parent_len, _child) = self.len_split(); + return ((parent_len + idx) as u32, data); } self.parent_generics.as_ref().unwrap().find_param(param) } -- cgit v1.2.3 From 29b5e1ec2a4bc25daddfe5137503b156b3cd283f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 7 Dec 2019 13:19:21 +0100 Subject: Reformat --- crates/ra_hir_ty/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 036d3a589..3ad913e55 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -44,8 +44,8 @@ use std::sync::Arc; use std::{fmt, iter, mem}; use hir_def::{ - expr::ExprId, type_ref::Mutability, AdtId, ContainerId, DefWithBodyId, - GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, + expr::ExprId, type_ref::Mutability, AdtId, ContainerId, DefWithBodyId, GenericDefId, HasModule, + Lookup, TraitId, TypeAliasId, }; use hir_expand::name::Name; use ra_db::{impl_intern_key, salsa, CrateId}; -- cgit v1.2.3 From 88c5b1282a5770097c6c768b24bedfc3a6944e08 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 7 Dec 2019 20:09:53 +0100 Subject: Rename GenericParam -> TypeParam We don't have LifetimeParam yet, but they are planned! --- crates/ra_hir_ty/src/utils.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 936cfe25e..aeb211a91 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -5,10 +5,10 @@ use std::sync::Arc; use hir_def::{ adt::VariantData, db::DefDatabase, - generics::{GenericParamData, GenericParams}, + generics::{GenericParams, TypeParamData}, resolver::{HasResolver, TypeNs}, type_ref::TypeRef, - ContainerId, GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId, VariantId, + ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, }; use hir_expand::name::{self, Name}; @@ -96,23 +96,21 @@ pub(crate) struct Generics { } impl Generics { - pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { + pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { self.parent_generics .as_ref() .into_iter() - .flat_map(|it| it.params.params.iter()) - .chain(self.params.params.iter()) + .flat_map(|it| it.params.types.iter()) + .chain(self.params.types.iter()) .enumerate() .map(|(i, (_local_id, p))| (i as u32, p)) } - pub(crate) fn iter_parent<'a>( - &'a self, - ) -> impl Iterator + 'a { + pub(crate) fn iter_parent<'a>(&'a self) -> impl Iterator + 'a { self.parent_generics .as_ref() .into_iter() - .flat_map(|it| it.params.params.iter()) + .flat_map(|it| it.params.types.iter()) .enumerate() .map(|(i, (_local_id, p))| (i as u32, p)) } @@ -123,20 +121,20 @@ impl Generics { /// (total, parents, child) pub(crate) fn len_split(&self) -> (usize, usize, usize) { let parent = self.parent_generics.as_ref().map_or(0, |p| p.len()); - let child = self.params.params.len(); + let child = self.params.types.len(); (parent + child, parent, child) } - pub(crate) fn param_idx(&self, param: GenericParamId) -> u32 { + pub(crate) fn param_idx(&self, param: TypeParamId) -> u32 { self.find_param(param).0 } - pub(crate) fn param_name(&self, param: GenericParamId) -> Name { + pub(crate) fn param_name(&self, param: TypeParamId) -> Name { self.find_param(param).1.name.clone() } - fn find_param(&self, param: GenericParamId) -> (u32, &GenericParamData) { + fn find_param(&self, param: TypeParamId) -> (u32, &TypeParamData) { if param.parent == self.def { let (idx, (_local_id, data)) = self .params - .params + .types .iter() .enumerate() .find(|(_, (idx, _))| *idx == param.local_id) -- cgit v1.2.3 From d0c9bb0abf764a3143fc0d13297d73184bc10397 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 8 Dec 2019 11:23:05 +0100 Subject: Fix coercion from &Foo to an inference variable in a reference We didn't try to unify within the reference, but we should. --- crates/ra_hir_ty/src/infer/coerce.rs | 6 +++++- crates/ra_hir_ty/src/tests/coercion.rs | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 9daa77cfa..0f4dac45e 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs @@ -332,7 +332,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // It will not recurse to `coerce`. return self.table.unify_substs(st1, st2, 0); } - _ => {} + _ => { + if self.table.unify_inner_trivial(&derefed_ty, &to_ty) { + return true; + } + } } } diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 58b22396f..ac9e3872a 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -403,3 +403,40 @@ fn test() { "### ); } + +#[test] +fn coerce_autoderef_generic() { + assert_snapshot!( + infer_with_mismatches(r#" +struct Foo; +fn takes_ref(x: &T) -> T { *x } +fn test() { + takes_ref(&Foo); + takes_ref(&&Foo); + takes_ref(&&&Foo); +} +"#, true), + @r###" + [29; 30) 'x': &T + [41; 47) '{ *x }': T + [43; 45) '*x': T + [44; 45) 'x': &T + [58; 127) '{ ...oo); }': () + [64; 73) 'takes_ref': fn takes_ref(&T) -> T + [64; 79) 'takes_ref(&Foo)': Foo + [74; 78) '&Foo': &Foo + [75; 78) 'Foo': Foo + [85; 94) 'takes_ref': fn takes_ref<&Foo>(&T) -> T + [85; 101) 'takes_...&&Foo)': &Foo + [95; 100) '&&Foo': &&Foo + [96; 100) '&Foo': &Foo + [97; 100) 'Foo': Foo + [107; 116) 'takes_ref': fn takes_ref<&&Foo>(&T) -> T + [107; 124) 'takes_...&&Foo)': &&Foo + [117; 123) '&&&Foo': &&&Foo + [118; 123) '&&Foo': &&Foo + [119; 123) '&Foo': &Foo + [120; 123) 'Foo': Foo + "### + ); +} -- cgit v1.2.3 From 16df4d8fcbf6695d8b033efe2dcaa5167629d9c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 9 Dec 2019 22:35:47 +0200 Subject: chore: bump deps and use mainline chalk --- crates/ra_hir_ty/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index 429242870..d277bf2bc 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml @@ -22,9 +22,9 @@ ra_syntax = { path = "../ra_syntax" } test_utils = { path = "../test_utils" } # https://github.com/rust-lang/chalk/pull/294 -chalk-solve = { git = "https://github.com/jackh726/chalk.git", rev = "095cd38a4f16337913bba487f2055b9ca0179f30" } -chalk-rust-ir = { git = "https://github.com/jackh726/chalk.git", rev = "095cd38a4f16337913bba487f2055b9ca0179f30" } -chalk-ir = { git = "https://github.com/jackh726/chalk.git", rev = "095cd38a4f16337913bba487f2055b9ca0179f30" } +chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "151949dece8117d180b5d197a7afa968c3ba14bb" } +chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "151949dece8117d180b5d197a7afa968c3ba14bb" } +chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "151949dece8117d180b5d197a7afa968c3ba14bb" } lalrpop-intern = "0.15.1" -- cgit v1.2.3 From 7b0644d81e52d00a7a6795b187f356213ff68225 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 12 Dec 2019 14:09:13 +0100 Subject: Switch to the new location for impls --- crates/ra_hir_ty/src/method_resolution.rs | 6 +++--- crates/ra_hir_ty/src/traits/chalk.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 7220d6e0a..848e306e9 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -6,8 +6,8 @@ use std::sync::Arc; use arrayvec::ArrayVec; use hir_def::{ - lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, AstItemDef, - FunctionId, HasModule, ImplId, Lookup, TraitId, + lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, FunctionId, + HasModule, ImplId, Lookup, TraitId, }; use hir_expand::name::Name; use ra_db::CrateId; @@ -134,7 +134,7 @@ impl Ty { LangItemTarget::ImplBlockId(it) => Some(it), _ => None, }) - .map(|it| it.module(db).krate) + .map(|it| it.lookup(db).container.krate) .collect(); Some(res) } diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 1e7ff93d5..ff299f511 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -673,7 +673,7 @@ fn impl_block_datum( let bound_vars = Substs::bound_vars(&generic_params); let trait_ref = trait_ref.subst(&bound_vars); let trait_ = trait_ref.trait_; - let impl_type = if impl_id.module(db).krate == krate { + let impl_type = if impl_id.lookup(db).container.krate == krate { chalk_rust_ir::ImplType::Local } else { chalk_rust_ir::ImplType::External -- cgit v1.2.3 From 82e9b245587046d2a1ed432225b19023adbe3245 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 12 Dec 2019 14:34:03 +0100 Subject: Move traits to the new loc --- crates/ra_hir_ty/src/traits/chalk.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index ff299f511..fc21872b2 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -9,9 +9,7 @@ use chalk_ir::{ }; use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; -use hir_def::{ - AssocItemId, AstItemDef, ContainerId, GenericDefId, ImplId, Lookup, TraitId, TypeAliasId, -}; +use hir_def::{AssocItemId, ContainerId, GenericDefId, ImplId, Lookup, TraitId, TypeAliasId}; use ra_db::{ salsa::{InternId, InternKey}, CrateId, @@ -593,7 +591,7 @@ pub(crate) fn trait_datum_query( let bound_vars = Substs::bound_vars(&generic_params); let flags = chalk_rust_ir::TraitFlags { auto: trait_data.auto, - upstream: trait_.module(db).krate != krate, + upstream: trait_.lookup(db).container.krate != krate, non_enumerable: true, coinductive: false, // only relevant for Chalk testing // FIXME set these flags correctly -- cgit v1.2.3 From f135a8ea55c0a46c67713fb3b79b5f62ada430c1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 12 Dec 2019 14:58:04 +0100 Subject: Move structs to new loc --- crates/ra_hir_ty/src/lower.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index eab91229e..6af5bf50a 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -699,7 +699,7 @@ impl CallableDef { pub fn krate(self, db: &impl HirDatabase) -> CrateId { match self { CallableDef::FunctionId(f) => f.lookup(db).module(db).krate, - CallableDef::StructId(s) => s.module(db).krate, + CallableDef::StructId(s) => s.lookup(db).container.krate, CallableDef::EnumVariantId(e) => e.parent.module(db).krate, } } -- cgit v1.2.3 From 56710f119b7114efac237ac36ea21730b8bd5311 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 12 Dec 2019 15:11:57 +0100 Subject: Move enum&union to new loc --- crates/ra_hir_ty/src/lower.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 6af5bf50a..5f795bc02 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -14,7 +14,7 @@ use hir_def::{ path::{GenericArg, Path, PathKind, PathSegment}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, - AdtId, AstItemDef, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, + AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, }; use ra_arena::map::ArenaMap; @@ -698,10 +698,11 @@ impl_froms!(CallableDef: FunctionId, StructId, EnumVariantId); impl CallableDef { pub fn krate(self, db: &impl HirDatabase) -> CrateId { match self { - CallableDef::FunctionId(f) => f.lookup(db).module(db).krate, - CallableDef::StructId(s) => s.lookup(db).container.krate, - CallableDef::EnumVariantId(e) => e.parent.module(db).krate, + CallableDef::FunctionId(f) => f.lookup(db).module(db), + CallableDef::StructId(s) => s.lookup(db).container, + CallableDef::EnumVariantId(e) => e.parent.lookup(db).container, } + .krate } } -- cgit v1.2.3 From 95dc2de8e979264e1c76ce5594e8a63547a7956e Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Fri, 13 Dec 2019 12:44:07 +0100 Subject: Add helper for resolving associated type of trait in infer --- crates/ra_hir_ty/src/infer.rs | 18 +++++++++++++ crates/ra_hir_ty/src/infer/expr.rs | 54 +++++--------------------------------- 2 files changed, 25 insertions(+), 47 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index d16f1eb46..62d5c8803 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -338,6 +338,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.table.resolve_ty_shallow(ty) } + fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option) -> Ty { + match assoc_ty { + Some(res_assoc_ty) => { + let ty = self.table.new_type_var(); + let projection = ProjectionPredicate { + ty: ty.clone(), + projection_ty: ProjectionTy { + associated_ty: res_assoc_ty, + parameters: Substs::single(inner_ty), + }, + }; + self.obligations.push(Obligation::Projection(projection)); + self.resolve_ty_as_possible(ty) + } + None => Ty::Unknown, + } + } + /// Recurses through the given type, normalizing associated types mentioned /// in it by replacing them by type variables and registering obligations to /// resolve later. This should be done once for every type we get from some diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 2c296987c..6110f5abd 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -19,8 +19,8 @@ use crate::{ method_resolution, op, traits::InEnvironment, utils::{generics, variant_data, Generics}, - CallableDef, InferTy, IntTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs, - TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, + ApplicationTy, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, Ty, + TypeCtor, TypeWalk, Uncertain, }; use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; @@ -95,21 +95,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Expr::For { iterable, body, pat } => { let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); - let pat_ty = match self.resolve_into_iter_item() { - Some(into_iter_item_alias) => { - let pat_ty = self.table.new_type_var(); - let projection = ProjectionPredicate { - ty: pat_ty.clone(), - projection_ty: ProjectionTy { - associated_ty: into_iter_item_alias, - parameters: Substs::single(iterable_ty), - }, - }; - self.obligations.push(Obligation::Projection(projection)); - self.resolve_ty_as_possible(pat_ty) - } - None => Ty::Unknown, - }; + let pat_ty = + self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); self.infer_pat(*pat, &pat_ty, BindingMode::default()); self.infer_expr(*body, &Expectation::has_type(Ty::unit())); @@ -284,40 +271,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } Expr::Await { expr } => { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); - let ty = match self.resolve_future_future_output() { - Some(future_future_output_alias) => { - let ty = self.table.new_type_var(); - let projection = ProjectionPredicate { - ty: ty.clone(), - projection_ty: ProjectionTy { - associated_ty: future_future_output_alias, - parameters: Substs::single(inner_ty), - }, - }; - self.obligations.push(Obligation::Projection(projection)); - self.resolve_ty_as_possible(ty) - } - None => Ty::Unknown, - }; + let ty = + self.resolve_associated_type(inner_ty, self.resolve_future_future_output()); ty } Expr::Try { expr } => { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); - let ty = match self.resolve_ops_try_ok() { - Some(ops_try_ok_alias) => { - let ty = self.table.new_type_var(); - let projection = ProjectionPredicate { - ty: ty.clone(), - projection_ty: ProjectionTy { - associated_ty: ops_try_ok_alias, - parameters: Substs::single(inner_ty), - }, - }; - self.obligations.push(Obligation::Projection(projection)); - self.resolve_ty_as_possible(ty) - } - None => Ty::Unknown, - }; + let ty = self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok()); ty } Expr::Cast { expr, type_ref } => { -- cgit v1.2.3 From 77052090515c1bb2a00236b3a57cdd778e581c8c Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Fri, 13 Dec 2019 12:44:42 +0100 Subject: Correctly infer - and ! using std::ops::{Neg,Not} --- crates/ra_hir_ty/src/infer.rs | 16 +++++++-- crates/ra_hir_ty/src/infer/expr.rs | 47 ++++++++++++++------------ crates/ra_hir_ty/src/tests/traits.rs | 64 ++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 23 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 62d5c8803..a1201b3e4 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -36,8 +36,8 @@ use ra_prof::profile; use super::{ primitive::{FloatTy, IntTy}, traits::{Guidance, Obligation, ProjectionPredicate, Solution}, - ApplicationTy, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, - Uncertain, + ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, + TypeWalk, Uncertain, }; use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; @@ -433,6 +433,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE) } + fn resolve_ops_neg_output(&self) -> Option { + let path = known::std_ops_neg(); + let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; + self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) + } + + fn resolve_ops_not_output(&self) -> Option { + let path = known::std_ops_not(); + let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; + self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) + } + fn resolve_future_future_output(&self) -> Option { let path = known::std_future_future(); let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 6110f5abd..f8c00a7b4 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -332,31 +332,36 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }, UnaryOp::Neg => { match &inner_ty { - Ty::Apply(a_ty) => match a_ty.ctor { - TypeCtor::Int(Uncertain::Unknown) - | TypeCtor::Int(Uncertain::Known(IntTy { - signedness: Signedness::Signed, - .. - })) - | TypeCtor::Float(..) => inner_ty, - _ => Ty::Unknown, - }, - Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => { - inner_ty - } - // FIXME: resolve ops::Neg trait - _ => Ty::Unknown, + // Fast path for builtins + Ty::Apply(ApplicationTy { + ctor: + TypeCtor::Int(Uncertain::Known(IntTy { + signedness: Signedness::Signed, + .. + })), + .. + }) + | Ty::Apply(ApplicationTy { + ctor: TypeCtor::Int(Uncertain::Unknown), + .. + }) + | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. }) + | Ty::Infer(InferTy::IntVar(..)) + | Ty::Infer(InferTy::FloatVar(..)) => inner_ty, + // Otherwise we resolve via the std::ops::Neg trait + _ => self + .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()), } } UnaryOp::Not => { match &inner_ty { - Ty::Apply(a_ty) => match a_ty.ctor { - TypeCtor::Bool | TypeCtor::Int(_) => inner_ty, - _ => Ty::Unknown, - }, - Ty::Infer(InferTy::IntVar(..)) => inner_ty, - // FIXME: resolve ops::Not trait for inner_ty - _ => Ty::Unknown, + // Fast path for builtins + Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. }) + | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(_), .. }) + | Ty::Infer(InferTy::IntVar(..)) => inner_ty, + // Otherwise we resolve via the std::ops::Not trait + _ => self + .resolve_associated_type(inner_ty, self.resolve_ops_not_output()), } } } diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 93c5f9a15..6139adb72 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -115,6 +115,70 @@ mod collections { assert_eq!("&str", type_at_pos(&db, pos)); } +#[test] +fn infer_ops_neg() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std + +struct Bar; +struct Foo; + +impl std::ops::Neg for Bar { + type Output = Foo; +} + +fn test() { + let a = Bar; + let b = -a; + b<|>; +} + +//- /std.rs crate:std + +#[prelude_import] use ops::*; +mod ops { + pub trait Neg { + type Output; + } +} +"#, + ); + assert_eq!("Foo", type_at_pos(&db, pos)); +} + +#[test] +fn infer_ops_not() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std + +struct Bar; +struct Foo; + +impl std::ops::Not for Bar { + type Output = Foo; +} + +fn test() { + let a = Bar; + let b = !a; + b<|>; +} + +//- /std.rs crate:std + +#[prelude_import] use ops::*; +mod ops { + pub trait Not { + type Output; + } +} +"#, + ); + assert_eq!("Foo", type_at_pos(&db, pos)); +} + #[test] fn infer_from_bound_1() { assert_snapshot!( -- cgit v1.2.3 From 259c42f00e2e85594c7373166bc8467ce375a045 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 13 Dec 2019 21:43:53 +0100 Subject: Add macros for known names and paths --- crates/ra_hir_ty/src/autoderef.rs | 4 ++-- crates/ra_hir_ty/src/infer.rs | 12 ++++++------ crates/ra_hir_ty/src/infer/expr.rs | 4 ++-- crates/ra_hir_ty/src/traits/builtin.rs | 6 +++--- crates/ra_hir_ty/src/utils.rs | 6 ++---- 5 files changed, 15 insertions(+), 17 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs index d557962b4..04822d56e 100644 --- a/crates/ra_hir_ty/src/autoderef.rs +++ b/crates/ra_hir_ty/src/autoderef.rs @@ -6,7 +6,7 @@ use std::iter::successors; use hir_def::lang_item::LangItemTarget; -use hir_expand::name; +use hir_expand::name::N; use log::{info, warn}; use ra_db::CrateId; @@ -52,7 +52,7 @@ fn deref_by_trait( LangItemTarget::TraitId(it) => it, _ => return None, }; - let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?; + let target = db.trait_data(deref_trait).associated_type_by_name(&N![Target])?; let generic_params = generics(db, target.into()); if generic_params.len() != 1 { diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index a1201b3e4..bb366bb8b 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -29,7 +29,7 @@ use hir_def::{ type_ref::{Mutability, TypeRef}, AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId, }; -use hir_expand::{diagnostics::DiagnosticSink, name}; +use hir_expand::{diagnostics::DiagnosticSink, name::N}; use ra_arena::map::ArenaMap; use ra_prof::profile; @@ -424,31 +424,31 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_into_iter_item(&self) -> Option { let path = known::std_iter_into_iterator(); let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; - self.db.trait_data(trait_).associated_type_by_name(&name::ITEM_TYPE) + self.db.trait_data(trait_).associated_type_by_name(&N![Item]) } fn resolve_ops_try_ok(&self) -> Option { let path = known::std_ops_try(); let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; - self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE) + self.db.trait_data(trait_).associated_type_by_name(&N![Ok]) } fn resolve_ops_neg_output(&self) -> Option { let path = known::std_ops_neg(); let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; - self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) + self.db.trait_data(trait_).associated_type_by_name(&N![Output]) } fn resolve_ops_not_output(&self) -> Option { let path = known::std_ops_not(); let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; - self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) + self.db.trait_data(trait_).associated_type_by_name(&N![Output]) } fn resolve_future_future_output(&self) -> Option { let path = known::std_future_future(); let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; - self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) + self.db.trait_data(trait_).associated_type_by_name(&N![Output]) } fn resolve_boxed_box(&self) -> Option { diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index f8c00a7b4..a6f5c6ec3 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -10,7 +10,7 @@ use hir_def::{ resolver::resolver_for_expr, AdtId, ContainerId, Lookup, StructFieldId, }; -use hir_expand::name::{self, Name}; +use hir_expand::name::{Name, N}; use ra_syntax::ast::RangeOp; use crate::{ @@ -631,7 +631,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // Parent arguments are unknown, except for the receiver type if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { for (_id, param) in parent_generics { - if param.name == name::SELF_TYPE { + if param.name == N![Self] { substs.push(receiver_ty.clone()); } else { substs.push(Ty::Unknown); diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index 598fd81e3..27c475a3c 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs @@ -1,7 +1,7 @@ //! This module provides the built-in trait implementations, e.g. to make //! closures implement `Fn`. use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId}; -use hir_expand::name; +use hir_expand::name::N; use ra_db::CrateId; use super::{AssocTyValue, Impl}; @@ -79,7 +79,7 @@ fn closure_fn_trait_impl_datum( // and don't want to return a valid value only to find out later that FnOnce // is broken let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; - let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?; + let _output = db.trait_data(fn_once_trait).associated_type_by_name(&N![Output])?; let num_args: u16 = match &db.body(data.def.into())[data.expr] { Expr::Lambda { args, .. } => args.len() as u16, @@ -137,7 +137,7 @@ fn closure_fn_trait_output_assoc_ty_value( let output_ty_id = db .trait_data(fn_once_trait) - .associated_type_by_name(&name::OUTPUT_TYPE) + .associated_type_by_name(&N![Output]) .expect("assoc ty value should not exist"); BuiltinImplAssocTyValueData { diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index aeb211a91..fabf45b53 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -10,10 +10,8 @@ use hir_def::{ type_ref::TypeRef, ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, }; -use hir_expand::name::{self, Name}; +use hir_expand::name::{Name, N}; -// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`. -// We should return a `TraitREf` here. fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec { let resolver = trait_.resolver(db); // returning the iterator directly doesn't easily work because of @@ -24,7 +22,7 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec { .where_predicates .iter() .filter_map(|pred| match &pred.type_ref { - TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(), + TypeRef::Path(p) if p.as_ident() == Some(&N![Self]) => pred.bound.as_path(), _ => None, }) .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { -- cgit v1.2.3 From 6911bc89a784ce72b4dfd8e0ba72bd22ce898395 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 13 Dec 2019 22:01:06 +0100 Subject: Rename N! to name! --- crates/ra_hir_ty/src/autoderef.rs | 4 ++-- crates/ra_hir_ty/src/infer.rs | 12 ++++++------ crates/ra_hir_ty/src/infer/expr.rs | 4 ++-- crates/ra_hir_ty/src/traits/builtin.rs | 6 +++--- crates/ra_hir_ty/src/utils.rs | 4 ++-- 5 files changed, 15 insertions(+), 15 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs index 04822d56e..ee48fa537 100644 --- a/crates/ra_hir_ty/src/autoderef.rs +++ b/crates/ra_hir_ty/src/autoderef.rs @@ -6,7 +6,7 @@ use std::iter::successors; use hir_def::lang_item::LangItemTarget; -use hir_expand::name::N; +use hir_expand::name::name; use log::{info, warn}; use ra_db::CrateId; @@ -52,7 +52,7 @@ fn deref_by_trait( LangItemTarget::TraitId(it) => it, _ => return None, }; - let target = db.trait_data(deref_trait).associated_type_by_name(&N![Target])?; + let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?; let generic_params = generics(db, target.into()); if generic_params.len() != 1 { diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index bb366bb8b..edf4e69ba 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -29,7 +29,7 @@ use hir_def::{ type_ref::{Mutability, TypeRef}, AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId, }; -use hir_expand::{diagnostics::DiagnosticSink, name::N}; +use hir_expand::{diagnostics::DiagnosticSink, name::name}; use ra_arena::map::ArenaMap; use ra_prof::profile; @@ -424,31 +424,31 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_into_iter_item(&self) -> Option { let path = known::std_iter_into_iterator(); let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; - self.db.trait_data(trait_).associated_type_by_name(&N![Item]) + self.db.trait_data(trait_).associated_type_by_name(&name![Item]) } fn resolve_ops_try_ok(&self) -> Option { let path = known::std_ops_try(); let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; - self.db.trait_data(trait_).associated_type_by_name(&N![Ok]) + self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) } fn resolve_ops_neg_output(&self) -> Option { let path = known::std_ops_neg(); let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; - self.db.trait_data(trait_).associated_type_by_name(&N![Output]) + self.db.trait_data(trait_).associated_type_by_name(&name![Output]) } fn resolve_ops_not_output(&self) -> Option { let path = known::std_ops_not(); let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; - self.db.trait_data(trait_).associated_type_by_name(&N![Output]) + self.db.trait_data(trait_).associated_type_by_name(&name![Output]) } fn resolve_future_future_output(&self) -> Option { let path = known::std_future_future(); let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; - self.db.trait_data(trait_).associated_type_by_name(&N![Output]) + self.db.trait_data(trait_).associated_type_by_name(&name![Output]) } fn resolve_boxed_box(&self) -> Option { diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index a6f5c6ec3..2e3cdd53a 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -10,7 +10,7 @@ use hir_def::{ resolver::resolver_for_expr, AdtId, ContainerId, Lookup, StructFieldId, }; -use hir_expand::name::{Name, N}; +use hir_expand::name::{name, Name}; use ra_syntax::ast::RangeOp; use crate::{ @@ -631,7 +631,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // Parent arguments are unknown, except for the receiver type if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { for (_id, param) in parent_generics { - if param.name == N![Self] { + if param.name == name![Self] { substs.push(receiver_ty.clone()); } else { substs.push(Ty::Unknown); diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index 27c475a3c..cd587a338 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs @@ -1,7 +1,7 @@ //! This module provides the built-in trait implementations, e.g. to make //! closures implement `Fn`. use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId}; -use hir_expand::name::N; +use hir_expand::name::name; use ra_db::CrateId; use super::{AssocTyValue, Impl}; @@ -79,7 +79,7 @@ fn closure_fn_trait_impl_datum( // and don't want to return a valid value only to find out later that FnOnce // is broken let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; - let _output = db.trait_data(fn_once_trait).associated_type_by_name(&N![Output])?; + let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; let num_args: u16 = match &db.body(data.def.into())[data.expr] { Expr::Lambda { args, .. } => args.len() as u16, @@ -137,7 +137,7 @@ fn closure_fn_trait_output_assoc_ty_value( let output_ty_id = db .trait_data(fn_once_trait) - .associated_type_by_name(&N![Output]) + .associated_type_by_name(&name![Output]) .expect("assoc ty value should not exist"); BuiltinImplAssocTyValueData { diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index fabf45b53..0049d3c6f 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -10,7 +10,7 @@ use hir_def::{ type_ref::TypeRef, ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, }; -use hir_expand::name::{Name, N}; +use hir_expand::name::{name, Name}; fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec { let resolver = trait_.resolver(db); @@ -22,7 +22,7 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec { .where_predicates .iter() .filter_map(|pred| match &pred.type_ref { - TypeRef::Path(p) if p.as_ident() == Some(&N![Self]) => pred.bound.as_path(), + TypeRef::Path(p) if p.as_ident() == Some(&name![Self]) => pred.bound.as_path(), _ => None, }) .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { -- cgit v1.2.3 From f02fcc16444fcd18ccd51b43fa01bf0233e044fa Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 13 Dec 2019 22:32:44 +0100 Subject: Use path macro --- crates/ra_hir_ty/src/expr.rs | 4 ++-- crates/ra_hir_ty/src/infer.rs | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index d2bd64e5c..f752a9f09 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use hir_def::{ - path::{known, Path}, + path::{path, Path}, resolver::HasResolver, AdtId, FunctionId, }; @@ -124,7 +124,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { None => return, }; - let std_result_path = known::std_result_result(); + let std_result_path = path![std::result::Result]; let resolver = self.func.resolver(db); let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index edf4e69ba..f1b7e9442 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -24,7 +24,7 @@ use hir_def::{ body::Body, data::{ConstData, FunctionData}, expr::{BindingAnnotation, ExprId, PatId}, - path::{known, Path}, + path::{path, Path}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{Mutability, TypeRef}, AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId, @@ -422,73 +422,73 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } fn resolve_into_iter_item(&self) -> Option { - let path = known::std_iter_into_iterator(); + let path = path![std::iter::IntoIterator]; let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; self.db.trait_data(trait_).associated_type_by_name(&name![Item]) } fn resolve_ops_try_ok(&self) -> Option { - let path = known::std_ops_try(); + let path = path![std::ops::Try]; let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) } fn resolve_ops_neg_output(&self) -> Option { - let path = known::std_ops_neg(); + let path = path![std::ops::Neg]; let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; self.db.trait_data(trait_).associated_type_by_name(&name![Output]) } fn resolve_ops_not_output(&self) -> Option { - let path = known::std_ops_not(); + let path = path![std::ops::Not]; let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; self.db.trait_data(trait_).associated_type_by_name(&name![Output]) } fn resolve_future_future_output(&self) -> Option { - let path = known::std_future_future(); + let path = path![std::future::Future]; let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; self.db.trait_data(trait_).associated_type_by_name(&name![Output]) } fn resolve_boxed_box(&self) -> Option { - let path = known::std_boxed_box(); + let path = path![std::boxed::Box]; let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; Some(struct_.into()) } fn resolve_range_full(&self) -> Option { - let path = known::std_ops_range_full(); + let path = path![std::ops::RangeFull]; let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; Some(struct_.into()) } fn resolve_range(&self) -> Option { - let path = known::std_ops_range(); + let path = path![std::ops::Range]; let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; Some(struct_.into()) } fn resolve_range_inclusive(&self) -> Option { - let path = known::std_ops_range_inclusive(); + let path = path![std::ops::RangeInclusive]; let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; Some(struct_.into()) } fn resolve_range_from(&self) -> Option { - let path = known::std_ops_range_from(); + let path = path![std::ops::RangeFrom]; let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; Some(struct_.into()) } fn resolve_range_to(&self) -> Option { - let path = known::std_ops_range_to(); + let path = path![std::ops::RangeTo]; let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; Some(struct_.into()) } fn resolve_range_to_inclusive(&self) -> Option { - let path = known::std_ops_range_to_inclusive(); + let path = path![std::ops::RangeToInclusive]; let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; Some(struct_.into()) } -- cgit v1.2.3 From 2619950b3b405324ab1c1745876165c834b3b4b9 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 13 Dec 2019 12:12:36 +0100 Subject: Use different types for path with and without generics --- crates/ra_hir_ty/src/infer.rs | 2 +- crates/ra_hir_ty/src/infer/path.rs | 25 +++++++------- crates/ra_hir_ty/src/lower.rs | 70 ++++++++++++++++++-------------------- crates/ra_hir_ty/src/utils.rs | 5 +-- 4 files changed, 51 insertions(+), 51 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index f1b7e9442..af42854cc 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -386,7 +386,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let resolver = &self.resolver; // FIXME: this should resolve assoc items as well, see this example: // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 - match resolver.resolve_path_in_type_ns_fully(self.db, &path) { + match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) { Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into()); let ty = self.db.ty(strukt.into()); diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 37db005ea..3bae0ca6c 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -32,21 +32,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { path: &Path, id: ExprOrPatId, ) -> Option { - let (value, self_subst) = if let PathKind::Type(type_ref) = &path.kind { - if path.segments.is_empty() { + let (value, self_subst) = if let PathKind::Type(type_ref) = path.kind() { + if path.segments().is_empty() { // This can't actually happen syntax-wise return None; } let ty = self.make_ty(type_ref); - let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1]; + let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); self.resolve_ty_assoc_item( ty, - &path.segments.last().expect("path had at least one segment").name, + &path.segments().last().expect("path had at least one segment").name, id, )? } else { - let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; + let value_or_partial = resolver.resolve_path_in_value_ns(self.db, path.mod_path())?; match value_or_partial { ResolveValueResult::ValueNs(it) => (it, None), @@ -85,13 +85,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { remaining_index: usize, id: ExprOrPatId, ) -> Option<(ValueNs, Option)> { - assert!(remaining_index < path.segments.len()); + assert!(remaining_index < path.segments().len()); // there may be more intermediate segments between the resolved one and // the end. Only the last segment needs to be resolved to a value; from // the segments before that, we need to get either a type or a trait ref. - let resolved_segment = &path.segments[remaining_index - 1]; - let remaining_segments = &path.segments[remaining_index..]; + let resolved_segment = path.segments().get(remaining_index - 1).unwrap(); + let remaining_segments = path.segments().skip(remaining_index); let is_before_last = remaining_segments.len() == 1; match (def, is_before_last) { @@ -112,7 +112,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // trait but it's not the last segment, so the next segment // should resolve to an associated type of that trait (e.g. `::Item::default`) - let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1]; + let remaining_segments_for_ty = + remaining_segments.take(remaining_segments.len() - 1); let ty = Ty::from_partly_resolved_hir_path( self.db, &self.resolver, @@ -138,7 +139,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_trait_assoc_item( &mut self, trait_ref: TraitRef, - segment: &PathSegment, + segment: PathSegment<'_>, id: ExprOrPatId, ) -> Option<(ValueNs, Option)> { let trait_ = trait_ref.trait_; @@ -150,7 +151,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { .map(|(_name, id)| (*id).into()) .find_map(|item| match item { AssocItemId::FunctionId(func) => { - if segment.name == self.db.function_data(func).name { + if segment.name == &self.db.function_data(func).name { Some(AssocItemId::FunctionId(func)) } else { None @@ -158,7 +159,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } AssocItemId::ConstId(konst) => { - if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == &segment.name) + if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == segment.name) { Some(AssocItemId::ConstId(konst)) } else { diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 5f795bc02..a4ddfc8ef 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use hir_def::{ builtin_type::BuiltinType, generics::WherePredicate, - path::{GenericArg, Path, PathKind, PathSegment}, + path::{GenericArg, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, @@ -101,13 +101,13 @@ impl Ty { TypeRef::Path(path) => path, _ => return None, }; - if let PathKind::Type(_) = &path.kind { + if let PathKind::Type(_) = path.kind() { return None; } - if path.segments.len() > 1 { + if path.segments().len() > 1 { return None; } - let resolution = match resolver.resolve_path_in_type_ns(db, path) { + let resolution = match resolver.resolve_path_in_type_ns(db, path.mod_path()) { Some((it, None)) => it, _ => return None, }; @@ -124,11 +124,11 @@ impl Ty { db: &impl HirDatabase, resolver: &Resolver, ty: Ty, - remaining_segments: &[PathSegment], + remaining_segments: PathSegments<'_>, ) -> Ty { if remaining_segments.len() == 1 { // resolve unselected assoc types - let segment = &remaining_segments[0]; + let segment = remaining_segments.first().unwrap(); Ty::select_associated_type(db, resolver, ty, segment) } else if remaining_segments.len() > 1 { // FIXME report error (ambiguous associated type) @@ -142,15 +142,15 @@ impl Ty { db: &impl HirDatabase, resolver: &Resolver, resolution: TypeNs, - resolved_segment: &PathSegment, - remaining_segments: &[PathSegment], + resolved_segment: PathSegment<'_>, + remaining_segments: PathSegments<'_>, ) -> Ty { let ty = match resolution { TypeNs::TraitId(trait_) => { let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None); return if remaining_segments.len() == 1 { - let segment = &remaining_segments[0]; + let segment = remaining_segments.first().unwrap(); let associated_ty = associated_type_by_name_including_super_traits( db, trait_ref.trait_, @@ -202,21 +202,21 @@ impl Ty { pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { // Resolve the path (in type namespace) - if let PathKind::Type(type_ref) = &path.kind { + if let PathKind::Type(type_ref) = path.kind() { let ty = Ty::from_hir(db, resolver, &type_ref); - let remaining_segments = &path.segments[..]; - return Ty::from_type_relative_path(db, resolver, ty, remaining_segments); + return Ty::from_type_relative_path(db, resolver, ty, path.segments()); } - let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { - Some(it) => it, - None => return Ty::Unknown, - }; + let (resolution, remaining_index) = + match resolver.resolve_path_in_type_ns(db, path.mod_path()) { + Some(it) => it, + None => return Ty::Unknown, + }; let (resolved_segment, remaining_segments) = match remaining_index { None => ( - path.segments.last().expect("resolved path has at least one element"), - &[] as &[PathSegment], + path.segments().last().expect("resolved path has at least one element"), + PathSegments::EMPTY, ), - Some(i) => (&path.segments[i - 1], &path.segments[i..]), + Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), }; Ty::from_partly_resolved_hir_path( db, @@ -231,7 +231,7 @@ impl Ty { db: &impl HirDatabase, resolver: &Resolver, self_ty: Ty, - segment: &PathSegment, + segment: PathSegment<'_>, ) -> Ty { let param_idx = match self_ty { Ty::Param { idx, .. } => idx, @@ -261,7 +261,7 @@ impl Ty { fn from_hir_path_inner( db: &impl HirDatabase, resolver: &Resolver, - segment: &PathSegment, + segment: PathSegment<'_>, typable: TyDefId, ) -> Ty { let generic_def = match typable { @@ -284,7 +284,7 @@ impl Ty { // special-case enum variants resolved: ValueTyDefId, ) -> Substs { - let last = path.segments.last().expect("path should have at least one segment"); + let last = path.segments().last().expect("path should have at least one segment"); let (segment, generic_def) = match resolved { ValueTyDefId::FunctionId(it) => (last, Some(it.into())), ValueTyDefId::StructId(it) => (last, Some(it.into())), @@ -296,13 +296,11 @@ impl Ty { // referring to the variant. So `Option::::None` and // `Option::None::` are both allowed (though the former is // preferred). See also `def_ids_for_path_segments` in rustc. - let len = path.segments.len(); - let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() { - // Option::::None - &path.segments[len - 2] - } else { - // Option::None:: - last + let len = path.segments().len(); + let penultimate = if len >= 2 { path.segments().get(len - 2) } else { None }; + let segment = match penultimate { + Some(segment) if segment.args_and_bindings.is_some() => segment, + _ => last, }; (segment, Some(var.parent.into())) } @@ -314,7 +312,7 @@ impl Ty { pub(super) fn substs_from_path_segment( db: &impl HirDatabase, resolver: &Resolver, - segment: &PathSegment, + segment: PathSegment<'_>, def_generic: Option, add_self_param: bool, ) -> Substs { @@ -372,11 +370,11 @@ impl TraitRef { path: &Path, explicit_self_ty: Option, ) -> Option { - let resolved = match resolver.resolve_path_in_type_ns_fully(db, &path)? { + let resolved = match resolver.resolve_path_in_type_ns_fully(db, path.mod_path())? { TypeNs::TraitId(tr) => tr, _ => return None, }; - let segment = path.segments.last().expect("path should have at least one segment"); + let segment = path.segments().last().expect("path should have at least one segment"); Some(TraitRef::from_resolved_path(db, resolver, resolved.into(), segment, explicit_self_ty)) } @@ -384,7 +382,7 @@ impl TraitRef { db: &impl HirDatabase, resolver: &Resolver, resolved: TraitId, - segment: &PathSegment, + segment: PathSegment<'_>, explicit_self_ty: Option, ) -> Self { let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); @@ -410,7 +408,7 @@ impl TraitRef { fn substs_from_path( db: &impl HirDatabase, resolver: &Resolver, - segment: &PathSegment, + segment: PathSegment<'_>, resolved: TraitId, ) -> Substs { let has_self_param = @@ -464,12 +462,12 @@ fn assoc_type_bindings_from_type_bound<'a>( trait_ref: TraitRef, ) -> impl Iterator + 'a { let last_segment = match bound { - TypeBound::Path(path) => path.segments.last(), + TypeBound::Path(path) => path.segments().last(), TypeBound::Error => None, }; last_segment .into_iter() - .flat_map(|segment| segment.args_and_bindings.iter()) + .flat_map(|segment| segment.args_and_bindings.into_iter()) .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) .map(move |(name, type_ref)| { let associated_ty = diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 0049d3c6f..29799a8cb 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -6,6 +6,7 @@ use hir_def::{ adt::VariantData, db::DefDatabase, generics::{GenericParams, TypeParamData}, + path::Path, resolver::{HasResolver, TypeNs}, type_ref::TypeRef, ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, @@ -22,10 +23,10 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec { .where_predicates .iter() .filter_map(|pred| match &pred.type_ref { - TypeRef::Path(p) if p.as_ident() == Some(&name![Self]) => pred.bound.as_path(), + TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(), _ => None, }) - .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { + .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { Some(TypeNs::TraitId(t)) => Some(t), _ => None, }) -- cgit v1.2.3 From ac961b261458bfeb23f7d4e896d5f957b0854a3a Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 6 Dec 2019 12:45:00 +0100 Subject: Add test for unifying impl Trait --- crates/ra_hir_ty/src/tests/traits.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 6139adb72..a926d01e5 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1,4 +1,4 @@ -use super::{infer, type_at, type_at_pos}; +use super::{infer, infer_with_mismatches, type_at, type_at_pos}; use crate::test_db::TestDB; use insta::assert_snapshot; use ra_db::fixture::WithFixture; @@ -1486,3 +1486,29 @@ fn test() where T: Trait, U: Trait { // this is a legitimate cycle assert_eq!(t, "{unknown}"); } + +#[test] +fn unify_impl_trait() { + assert_snapshot!( + infer_with_mismatches(r#" +trait Trait {} + +fn foo(x: impl Trait) { loop {} } +fn bar(x: impl Trait) -> T { loop {} } + +struct S(T); +impl Trait for S {} + +fn default() -> T { loop {} } + +fn test() -> impl Trait { + let s1 = S(default()); + foo(s1); + let x: i32 = bar(S(default())); + S(default()) +} +"#, true), + @r###" + "### + ); +} -- cgit v1.2.3 From 6e1c2d0df89a390be33c81b6e03a5ad352763593 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 15 Dec 2019 18:56:38 +0100 Subject: Handle impl Trait more correctly When calling a function, argument-position impl Trait is transparent; same for return-position impl Trait when inside the function. So in these cases, we need to represent that type not by `Ty::Opaque`, but by a type variable that can be unified with whatever flows into there. --- crates/ra_hir_ty/src/infer.rs | 25 ++++++++++++++++++++++++- crates/ra_hir_ty/src/infer/expr.rs | 1 + crates/ra_hir_ty/src/tests/traits.rs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index af42854cc..1aa1330a6 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -274,6 +274,28 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.normalize_associated_types_in(ty) } + /// Replaces `impl Trait` in `ty` by type variables and obligations for + /// those variables. This is done for function arguments when calling a + /// function, and for return types when inside the function body, i.e. in + /// the cases where the `impl Trait` is 'transparent'. In other cases, `impl + /// Trait` is represented by `Ty::Opaque`. + fn insert_vars_for_impl_trait(&mut self, ty: Ty) -> Ty { + ty.fold(&mut |ty| match ty { + Ty::Opaque(preds) => { + let var = self.table.new_type_var(); + let var_subst = Substs::builder(1).push(var.clone()).build(); + self.obligations.extend( + preds + .iter() + .map(|pred| pred.clone().subst_bound_vars(&var_subst)) + .filter_map(Obligation::from_predicate), + ); + var + } + _ => ty, + }) + } + /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { match ty { @@ -414,7 +436,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.infer_pat(*pat, &ty, BindingMode::default()); } - self.return_ty = self.make_ty(&data.ret_type); + let return_ty = self.make_ty(&data.ret_type); + self.return_ty = self.insert_vars_for_impl_trait(return_ty); } fn infer_body(&mut self) { diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 2e3cdd53a..924ad3e81 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -613,6 +613,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { continue; } + let param_ty = self.insert_vars_for_impl_trait(param_ty); let param_ty = self.normalize_associated_types_in(param_ty); self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); } diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index a926d01e5..d8673c90d 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1509,6 +1509,37 @@ fn test() -> impl Trait { } "#, true), @r###" + [27; 28) 'x': impl Trait + [47; 58) '{ loop {} }': () + [49; 56) 'loop {}': ! + [54; 56) '{}': () + [69; 70) 'x': impl Trait + [92; 103) '{ loop {} }': T + [94; 101) 'loop {}': ! + [99; 101) '{}': () + [172; 183) '{ loop {} }': T + [174; 181) 'loop {}': ! + [179; 181) '{}': () + [214; 310) '{ ...t()) }': S + [224; 226) 's1': S + [229; 230) 'S': S(T) -> S + [229; 241) 'S(default())': S + [231; 238) 'default': fn default() -> T + [231; 240) 'default()': u32 + [247; 250) 'foo': fn foo(impl Trait) -> () + [247; 254) 'foo(s1)': () + [251; 253) 's1': S + [264; 265) 'x': i32 + [273; 276) 'bar': fn bar(impl Trait) -> T + [273; 290) 'bar(S(...lt()))': i32 + [277; 278) 'S': S(T) -> S + [277; 289) 'S(default())': S + [279; 286) 'default': fn default() -> T + [279; 288) 'default()': i32 + [296; 297) 'S': S(T) -> S + [296; 308) 'S(default())': S + [298; 305) 'default': fn default() -> T + [298; 307) 'default()': i32 "### ); } -- cgit v1.2.3 From 91853590a9ee78406e892ca92305edef3a5b9213 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 15 Dec 2019 21:06:08 +0100 Subject: Add test mark --- crates/ra_hir_ty/src/infer.rs | 2 ++ crates/ra_hir_ty/src/marks.rs | 1 + crates/ra_hir_ty/src/tests/traits.rs | 8 ++++++-- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 1aa1330a6..98ba05fc2 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -32,6 +32,7 @@ use hir_def::{ use hir_expand::{diagnostics::DiagnosticSink, name::name}; use ra_arena::map::ArenaMap; use ra_prof::profile; +use test_utils::tested_by; use super::{ primitive::{FloatTy, IntTy}, @@ -282,6 +283,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn insert_vars_for_impl_trait(&mut self, ty: Ty) -> Ty { ty.fold(&mut |ty| match ty { Ty::Opaque(preds) => { + tested_by!(insert_vars_for_impl_trait); let var = self.table.new_type_var(); let var_subst = Substs::builder(1).push(var.clone()).build(); self.obligations.extend( diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs index 0f754eb9c..fe74acf11 100644 --- a/crates/ra_hir_ty/src/marks.rs +++ b/crates/ra_hir_ty/src/marks.rs @@ -6,4 +6,5 @@ test_utils::marks!( type_var_resolves_to_int_var match_ergonomics_ref coerce_merge_fail_fallback + insert_vars_for_impl_trait ); diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index d8673c90d..802937cb0 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1,7 +1,10 @@ -use super::{infer, infer_with_mismatches, type_at, type_at_pos}; -use crate::test_db::TestDB; use insta::assert_snapshot; + use ra_db::fixture::WithFixture; +use test_utils::covers; + +use super::{infer, infer_with_mismatches, type_at, type_at_pos}; +use crate::test_db::TestDB; #[test] fn infer_await() { @@ -1489,6 +1492,7 @@ fn test() where T: Trait, U: Trait { #[test] fn unify_impl_trait() { + covers!(insert_vars_for_impl_trait); assert_snapshot!( infer_with_mismatches(r#" trait Trait {} -- cgit v1.2.3 From 04715cbe1caf92e55d393a352a12454ba958845e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 18 Dec 2019 17:41:33 +0100 Subject: Forbid ::foo syntax in mod paths --- crates/ra_hir_ty/src/infer/path.rs | 4 ++-- crates/ra_hir_ty/src/lower.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 3bae0ca6c..402a89386 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -3,7 +3,7 @@ use std::iter; use hir_def::{ - path::{Path, PathKind, PathSegment}, + path::{Path, PathSegment}, resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, AssocItemId, ContainerId, Lookup, }; @@ -32,7 +32,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { path: &Path, id: ExprOrPatId, ) -> Option { - let (value, self_subst) = if let PathKind::Type(type_ref) = path.kind() { + let (value, self_subst) = if let Some(type_ref) = path.type_anchor() { if path.segments().is_empty() { // This can't actually happen syntax-wise return None; diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index a4ddfc8ef..2b84309d7 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use hir_def::{ builtin_type::BuiltinType, generics::WherePredicate, - path::{GenericArg, Path, PathKind, PathSegment, PathSegments}, + path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, @@ -101,7 +101,7 @@ impl Ty { TypeRef::Path(path) => path, _ => return None, }; - if let PathKind::Type(_) = path.kind() { + if path.type_anchor().is_some() { return None; } if path.segments().len() > 1 { @@ -202,7 +202,7 @@ impl Ty { pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { // Resolve the path (in type namespace) - if let PathKind::Type(type_ref) = path.kind() { + if let Some(type_ref) = path.type_anchor() { let ty = Ty::from_hir(db, resolver, &type_ref); return Ty::from_type_relative_path(db, resolver, ty, path.segments()); } -- cgit v1.2.3 From dddee23f43a0e1939124a607ba534e69a810843a Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Thu, 19 Dec 2019 12:45:07 +0800 Subject: Add std::ops::Index support for infering --- crates/ra_hir_ty/src/infer.rs | 22 +++++++++++++++++++++- crates/ra_hir_ty/src/infer/expr.rs | 12 ++++++++---- crates/ra_hir_ty/src/tests/traits.rs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 5 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 98ba05fc2..14bfdde3d 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -363,14 +363,28 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option) -> Ty { + self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[]) + } + + fn resolve_associated_type_with_params( + &mut self, + inner_ty: Ty, + assoc_ty: Option, + params: &[Ty], + ) -> Ty { match assoc_ty { Some(res_assoc_ty) => { let ty = self.table.new_type_var(); + let mut builder = Substs::builder(1 + params.len()).push(inner_ty); + for ty in params { + builder = builder.push(ty.clone()); + } + let projection = ProjectionPredicate { ty: ty.clone(), projection_ty: ProjectionTy { associated_ty: res_assoc_ty, - parameters: Substs::single(inner_ty), + parameters: builder.build(), }, }; self.obligations.push(Obligation::Projection(projection)); @@ -517,6 +531,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; Some(struct_.into()) } + + fn resolve_ops_index_output(&self) -> Option { + let path = path![std::ops::Index]; + let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; + self.db.trait_data(trait_).associated_type_by_name(&name![Output]) + } } /// The kinds of placeholders we need during type inference. There's separate diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 924ad3e81..011c6c5c6 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -422,10 +422,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } Expr::Index { base, index } => { - let _base_ty = self.infer_expr_inner(*base, &Expectation::none()); - let _index_ty = self.infer_expr(*index, &Expectation::none()); - // FIXME: use `std::ops::Index::Output` to figure out the real return type - Ty::Unknown + let base_ty = self.infer_expr_inner(*base, &Expectation::none()); + let index_ty = self.infer_expr(*index, &Expectation::none()); + + self.resolve_associated_type_with_params( + base_ty, + self.resolve_ops_index_output(), + &[index_ty], + ) } Expr::Tuple { exprs } => { let mut tys = match &expected.ty { diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 802937cb0..2d92a5eec 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -426,6 +426,38 @@ fn indexing_arrays() { ) } +#[test] +fn infer_ops_index() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std + +struct Bar; +struct Foo; + +impl std::ops::Index for Bar { + type Output = Foo; +} + +fn test() { + let a = Bar; + let b = a[1]; + b<|>; +} + +//- /std.rs crate:std + +#[prelude_import] use ops::*; +mod ops { + pub trait Index { + type Output; + } +} +"#, + ); + assert_eq!("Foo", type_at_pos(&db, pos)); +} + #[test] fn deref_trait() { let t = type_at( -- cgit v1.2.3 From 14c167a9f6da07024a5101ffa04bc2f79ce64353 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 8 Dec 2019 00:54:18 +0200 Subject: Omit default parameter types --- crates/ra_hir_ty/src/display.rs | 21 +++++++++++++++------ crates/ra_hir_ty/src/lib.rs | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 7 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs index 9bb3ece6c..9176c0629 100644 --- a/crates/ra_hir_ty/src/display.rs +++ b/crates/ra_hir_ty/src/display.rs @@ -9,7 +9,7 @@ pub struct HirFormatter<'a, 'b, DB> { fmt: &'a mut fmt::Formatter<'b>, buf: String, curr_size: usize, - max_size: Option, + truncate_options: Option<&'a TruncateOptions>, } pub trait HirDisplay { @@ -25,12 +25,12 @@ pub trait HirDisplay { fn display_truncated<'a, DB>( &'a self, db: &'a DB, - max_size: Option, + truncate_options: &'a TruncateOptions, ) -> HirDisplayWrapper<'a, DB, Self> where Self: Sized, { - HirDisplayWrapper(db, self, max_size) + HirDisplayWrapper(db, self, Some(truncate_options)) } } @@ -66,15 +66,24 @@ where } pub fn should_truncate(&self) -> bool { - if let Some(max_size) = self.max_size { + if let Some(max_size) = self.truncate_options.and_then(|options| options.max_length) { self.curr_size >= max_size } else { false } } + + pub fn should_display_default_types(&self) -> bool { + self.truncate_options.map(|options| options.show_default_types).unwrap_or(true) + } +} + +pub struct TruncateOptions { + pub max_length: Option, + pub show_default_types: bool, } -pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T, Option); +pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T, Option<&'a TruncateOptions>); impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T> where @@ -87,7 +96,7 @@ where fmt: f, buf: String::with_capacity(20), curr_size: 0, - max_size: self.2, + truncate_options: self.2, }) } } diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 3ad913e55..7ca9e6b8a 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -906,7 +906,38 @@ impl HirDisplay for ApplicationTy { write!(f, "{}", name)?; if self.parameters.len() > 0 { write!(f, "<")?; - f.write_joined(&*self.parameters.0, ", ")?; + + let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); + let parameters_to_write = if f.should_display_default_types() { + self.parameters.0.as_ref() + } else { + match self + .ctor + .as_generic_def() + .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) + .filter(|defaults| !defaults.is_empty()) + { + Option::None => self.parameters.0.as_ref(), + Option::Some(default_parameters) => { + for (i, parameter) in self.parameters.into_iter().enumerate() { + match (parameter, default_parameters.get(i)) { + (&Ty::Unknown, _) | (_, None) => { + non_default_parameters.push(parameter.clone()) + } + (_, Some(default_parameter)) + if parameter != default_parameter => + { + non_default_parameters.push(parameter.clone()) + } + _ => (), + } + } + &non_default_parameters + } + } + }; + + f.write_joined(parameters_to_write, ", ")?; write!(f, ">")?; } } -- cgit v1.2.3 From b61ad6a96430f82e9724c1831d7402705145750e Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Thu, 19 Dec 2019 22:28:52 +0800 Subject: Use build_for_def --- crates/ra_hir_ty/src/infer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 14bfdde3d..98baeed6f 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -375,7 +375,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { match assoc_ty { Some(res_assoc_ty) => { let ty = self.table.new_type_var(); - let mut builder = Substs::builder(1 + params.len()).push(inner_ty); + let mut builder = Substs::build_for_def(self.db, res_assoc_ty).push(inner_ty); for ty in params { builder = builder.push(ty.clone()); } -- cgit v1.2.3 From 4ed78f80f4cc3cf32681fce6722293da6c8df76d Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 19 Dec 2019 16:43:41 +0200 Subject: Remove TruncateOptions struct --- crates/ra_hir_ty/src/display.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs index 9176c0629..dcca1bace 100644 --- a/crates/ra_hir_ty/src/display.rs +++ b/crates/ra_hir_ty/src/display.rs @@ -9,7 +9,8 @@ pub struct HirFormatter<'a, 'b, DB> { fmt: &'a mut fmt::Formatter<'b>, buf: String, curr_size: usize, - truncate_options: Option<&'a TruncateOptions>, + max_size: Option, + should_display_default_types: bool, } pub trait HirDisplay { @@ -19,18 +20,18 @@ pub trait HirDisplay { where Self: Sized, { - HirDisplayWrapper(db, self, None) + HirDisplayWrapper(db, self, None, true) } fn display_truncated<'a, DB>( &'a self, db: &'a DB, - truncate_options: &'a TruncateOptions, + max_size: Option, ) -> HirDisplayWrapper<'a, DB, Self> where Self: Sized, { - HirDisplayWrapper(db, self, Some(truncate_options)) + HirDisplayWrapper(db, self, max_size, false) } } @@ -66,7 +67,7 @@ where } pub fn should_truncate(&self) -> bool { - if let Some(max_size) = self.truncate_options.and_then(|options| options.max_length) { + if let Some(max_size) = self.max_size { self.curr_size >= max_size } else { false @@ -74,16 +75,11 @@ where } pub fn should_display_default_types(&self) -> bool { - self.truncate_options.map(|options| options.show_default_types).unwrap_or(true) + self.should_display_default_types } } -pub struct TruncateOptions { - pub max_length: Option, - pub show_default_types: bool, -} - -pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T, Option<&'a TruncateOptions>); +pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T, Option, bool); impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T> where @@ -96,7 +92,8 @@ where fmt: f, buf: String::with_capacity(20), curr_size: 0, - truncate_options: self.2, + max_size: self.2, + should_display_default_types: self.3, }) } } -- cgit v1.2.3 From ba12e83c26b24358e1bfbae0f913f8dfa13fc68f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 19 Dec 2019 18:12:46 +0100 Subject: Add body as a possible container for items --- crates/ra_hir_ty/src/infer/path.rs | 2 +- crates/ra_hir_ty/src/method_resolution.rs | 10 +++++----- crates/ra_hir_ty/src/utils.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 402a89386..31c90ea1e 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -237,7 +237,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { })); Some(substs) } - ContainerId::ModuleId(_) => None, + ContainerId::ModuleId(_) | ContainerId::DefWithBodyId(_) => None, }; self.write_assoc_resolution(id, item.into()); diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 848e306e9..d0b2b016d 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -6,8 +6,8 @@ use std::sync::Arc; use arrayvec::ArrayVec; use hir_def::{ - lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, FunctionId, - HasModule, ImplId, Lookup, TraitId, + lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, ContainerId, + FunctionId, HasModule, ImplId, Lookup, TraitId, }; use hir_expand::name::Name; use ra_db::CrateId; @@ -451,12 +451,12 @@ fn transform_receiver_ty( self_ty: &Canonical, ) -> Option { let substs = match function_id.lookup(db).container { - hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, function_id) + ContainerId::TraitId(_) => Substs::build_for_def(db, function_id) .push(self_ty.value.clone()) .fill_with_unknown() .build(), - hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?, - hir_def::ContainerId::ModuleId(_) => unreachable!(), + ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?, + ContainerId::ModuleId(_) | ContainerId::DefWithBodyId(_) => unreachable!(), }; let sig = db.callable_item_signature(function_id.into()); Some(sig.params()[0].clone().subst(&substs)) diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 29799a8cb..34defc1a2 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -157,6 +157,6 @@ fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option Some(it.into()), ContainerId::TraitId(it) => Some(it.into()), - ContainerId::ModuleId(_) => None, + ContainerId::ModuleId(_) | ContainerId::DefWithBodyId(_) => None, } } -- cgit v1.2.3 From 76d688a328ab53b6264f9e489b88524377a7271d Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Fri, 20 Dec 2019 03:04:55 +0800 Subject: Use fill instread of for loop --- crates/ra_hir_ty/src/infer.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 98baeed6f..bbbc391c4 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -375,11 +375,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { match assoc_ty { Some(res_assoc_ty) => { let ty = self.table.new_type_var(); - let mut builder = Substs::build_for_def(self.db, res_assoc_ty).push(inner_ty); - for ty in params { - builder = builder.push(ty.clone()); - } - + let builder = Substs::build_for_def(self.db, res_assoc_ty) + .push(inner_ty) + .fill(params.iter().cloned()); let projection = ProjectionPredicate { ty: ty.clone(), projection_ty: ProjectionTy { -- cgit v1.2.3 From 8fc20b65035d93bcc1b3a89127916bd165a8d938 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 20 Dec 2019 11:59:50 +0100 Subject: Rename ContainerId -> AssocContainerId --- crates/ra_hir_ty/src/infer/expr.rs | 4 ++-- crates/ra_hir_ty/src/infer/path.rs | 8 ++++---- crates/ra_hir_ty/src/lib.rs | 8 ++++---- crates/ra_hir_ty/src/method_resolution.rs | 10 +++++----- crates/ra_hir_ty/src/traits/chalk.rs | 6 +++--- crates/ra_hir_ty/src/utils.rs | 8 ++++---- 6 files changed, 22 insertions(+), 22 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 924ad3e81..6917c183b 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -8,7 +8,7 @@ use hir_def::{ expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, path::{GenericArg, GenericArgs}, resolver::resolver_for_expr, - AdtId, ContainerId, Lookup, StructFieldId, + AdtId, AssocContainerId, Lookup, StructFieldId, }; use hir_expand::name::{name, Name}; use ra_syntax::ast::RangeOp; @@ -672,7 +672,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // add obligation for trait implementation, if this is a trait method match def { CallableDef::FunctionId(f) => { - if let ContainerId::TraitId(trait_) = f.lookup(self.db).container { + if let AssocContainerId::TraitId(trait_) = f.lookup(self.db).container { // construct a TraitDef let substs = a_ty.parameters.prefix(generics(self.db, trait_.into()).len()); diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 31c90ea1e..a96ab75d1 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -5,7 +5,7 @@ use std::iter; use hir_def::{ path::{Path, PathSegment}, resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, - AssocItemId, ContainerId, Lookup, + AssocContainerId, AssocItemId, Lookup, }; use hir_expand::name::Name; @@ -209,7 +209,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { AssocItemId::TypeAliasId(_) => unreachable!(), }; let substs = match container { - ContainerId::ImplId(impl_id) => { + AssocContainerId::ImplId(impl_id) => { let impl_substs = Substs::build_for_def(self.db, impl_id) .fill(iter::repeat_with(|| self.table.new_type_var())) .build(); @@ -221,7 +221,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.unify(&impl_self_ty, &ty); Some(substs) } - ContainerId::TraitId(trait_) => { + AssocContainerId::TraitId(trait_) => { // we're picking this method let trait_substs = Substs::build_for_def(self.db, trait_) .push(ty.clone()) @@ -237,7 +237,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { })); Some(substs) } - ContainerId::ModuleId(_) | ContainerId::DefWithBodyId(_) => None, + AssocContainerId::ModuleId(_) | AssocContainerId::DefWithBodyId(_) => None, }; self.write_assoc_resolution(id, item.into()); diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 7ca9e6b8a..7310ef10d 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -44,8 +44,8 @@ use std::sync::Arc; use std::{fmt, iter, mem}; use hir_def::{ - expr::ExprId, type_ref::Mutability, AdtId, ContainerId, DefWithBodyId, GenericDefId, HasModule, - Lookup, TraitId, TypeAliasId, + expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, + HasModule, Lookup, TraitId, TypeAliasId, }; use hir_expand::name::Name; use ra_db::{impl_intern_key, salsa, CrateId}; @@ -251,7 +251,7 @@ impl ProjectionTy { fn trait_(&self, db: &impl HirDatabase) -> TraitId { match self.associated_ty.lookup(db).container { - ContainerId::TraitId(it) => it, + AssocContainerId::TraitId(it) => it, _ => panic!("projection ty without parent trait"), } } @@ -943,7 +943,7 @@ impl HirDisplay for ApplicationTy { } TypeCtor::AssociatedType(type_alias) => { let trait_ = match type_alias.lookup(f.db).container { - ContainerId::TraitId(it) => it, + AssocContainerId::TraitId(it) => it, _ => panic!("not an associated type"), }; let trait_name = f.db.trait_data(trait_).name.clone(); diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index d0b2b016d..1c2e7b934 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -6,8 +6,8 @@ use std::sync::Arc; use arrayvec::ArrayVec; use hir_def::{ - lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, ContainerId, - FunctionId, HasModule, ImplId, Lookup, TraitId, + lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocContainerId, + AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId, }; use hir_expand::name::Name; use ra_db::CrateId; @@ -451,12 +451,12 @@ fn transform_receiver_ty( self_ty: &Canonical, ) -> Option { let substs = match function_id.lookup(db).container { - ContainerId::TraitId(_) => Substs::build_for_def(db, function_id) + AssocContainerId::TraitId(_) => Substs::build_for_def(db, function_id) .push(self_ty.value.clone()) .fill_with_unknown() .build(), - ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?, - ContainerId::ModuleId(_) | ContainerId::DefWithBodyId(_) => unreachable!(), + AssocContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?, + AssocContainerId::ModuleId(_) | AssocContainerId::DefWithBodyId(_) => unreachable!(), }; let sig = db.callable_item_signature(function_id.into()); Some(sig.params()[0].clone().subst(&substs)) diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index fc21872b2..6a31014d8 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -9,7 +9,7 @@ use chalk_ir::{ }; use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; -use hir_def::{AssocItemId, ContainerId, GenericDefId, ImplId, Lookup, TraitId, TypeAliasId}; +use hir_def::{AssocContainerId, AssocItemId, GenericDefId, ImplId, Lookup, TraitId, TypeAliasId}; use ra_db::{ salsa::{InternId, InternKey}, CrateId, @@ -542,7 +542,7 @@ pub(crate) fn associated_ty_data_query( debug!("associated_ty_data {:?}", id); let type_alias: TypeAliasId = from_chalk(db, id); let trait_ = match type_alias.lookup(db).container { - ContainerId::TraitId(t) => t, + AssocContainerId::TraitId(t) => t, _ => panic!("associated type not in trait"), }; let generic_params = generics(db, type_alias.into()); @@ -755,7 +755,7 @@ fn type_alias_associated_ty_value( ) -> Arc> { let type_alias_data = db.type_alias_data(type_alias); let impl_id = match type_alias.lookup(db).container { - ContainerId::ImplId(it) => it, + AssocContainerId::ImplId(it) => it, _ => panic!("assoc ty value should be in impl"), }; diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 34defc1a2..8b5b611ec 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -9,7 +9,7 @@ use hir_def::{ path::Path, resolver::{HasResolver, TypeNs}, type_ref::TypeRef, - ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, + AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, }; use hir_expand::name::{name, Name}; @@ -155,8 +155,8 @@ fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option Some(it.into()), - ContainerId::TraitId(it) => Some(it.into()), - ContainerId::ModuleId(_) | ContainerId::DefWithBodyId(_) => None, + AssocContainerId::ImplId(it) => Some(it.into()), + AssocContainerId::TraitId(it) => Some(it.into()), + AssocContainerId::ModuleId(_) | AssocContainerId::DefWithBodyId(_) => None, } } -- cgit v1.2.3 From 94ad07af4bef6a70602e315bf315c6fce95618dd Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 20 Dec 2019 12:07:23 +0100 Subject: Introduce `ContainerId` --- crates/ra_hir_ty/src/infer/path.rs | 2 +- crates/ra_hir_ty/src/method_resolution.rs | 2 +- crates/ra_hir_ty/src/utils.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index a96ab75d1..ffd358367 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -237,7 +237,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { })); Some(substs) } - AssocContainerId::ModuleId(_) | AssocContainerId::DefWithBodyId(_) => None, + AssocContainerId::ContainerId(_) => None, }; self.write_assoc_resolution(id, item.into()); diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 1c2e7b934..1b2f4014c 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -456,7 +456,7 @@ fn transform_receiver_ty( .fill_with_unknown() .build(), AssocContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?, - AssocContainerId::ModuleId(_) | AssocContainerId::DefWithBodyId(_) => unreachable!(), + AssocContainerId::ContainerId(_) => unreachable!(), }; let sig = db.callable_item_signature(function_id.into()); Some(sig.params()[0].clone().subst(&substs)) diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 8b5b611ec..0b1806a84 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -157,6 +157,6 @@ fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option Some(it.into()), AssocContainerId::TraitId(it) => Some(it.into()), - AssocContainerId::ModuleId(_) | AssocContainerId::DefWithBodyId(_) => None, + AssocContainerId::ContainerId(_) => None, } } -- cgit v1.2.3 From ac5a3f611b05dbedd286169539335ae9f0fbb7b0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 20 Dec 2019 12:20:49 +0100 Subject: Support for nested ADT --- crates/ra_hir_ty/src/lower.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 2b84309d7..af3db2e1d 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -697,8 +697,8 @@ impl CallableDef { pub fn krate(self, db: &impl HirDatabase) -> CrateId { match self { CallableDef::FunctionId(f) => f.lookup(db).module(db), - CallableDef::StructId(s) => s.lookup(db).container, - CallableDef::EnumVariantId(e) => e.parent.lookup(db).container, + CallableDef::StructId(s) => s.lookup(db).container.module(db), + CallableDef::EnumVariantId(e) => e.parent.lookup(db).container.module(db), } .krate } -- cgit v1.2.3 From f42697e54b9d0a040011cb04c266d51710e249f1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 20 Dec 2019 12:29:25 +0100 Subject: Support for nested traits --- crates/ra_hir_ty/src/traits/chalk.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 6a31014d8..dd4fa9664 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -9,7 +9,9 @@ use chalk_ir::{ }; use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; -use hir_def::{AssocContainerId, AssocItemId, GenericDefId, ImplId, Lookup, TraitId, TypeAliasId}; +use hir_def::{ + AssocContainerId, AssocItemId, GenericDefId, HasModule, ImplId, Lookup, TraitId, TypeAliasId, +}; use ra_db::{ salsa::{InternId, InternKey}, CrateId, @@ -591,7 +593,7 @@ pub(crate) fn trait_datum_query( let bound_vars = Substs::bound_vars(&generic_params); let flags = chalk_rust_ir::TraitFlags { auto: trait_data.auto, - upstream: trait_.lookup(db).container.krate != krate, + upstream: trait_.lookup(db).container.module(db).krate != krate, non_enumerable: true, coinductive: false, // only relevant for Chalk testing // FIXME set these flags correctly -- cgit v1.2.3 From 1234dda9ee60a19a83a9664c2e1208247566b49b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 20 Dec 2019 13:47:44 +0100 Subject: Use generic ItemLoc for impls --- crates/ra_hir_ty/src/method_resolution.rs | 2 +- crates/ra_hir_ty/src/traits/chalk.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 1b2f4014c..92fb4c081 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -134,7 +134,7 @@ impl Ty { LangItemTarget::ImplBlockId(it) => Some(it), _ => None, }) - .map(|it| it.lookup(db).container.krate) + .map(|it| it.lookup(db).container.module(db).krate) .collect(); Some(res) } diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index dd4fa9664..5eb032d86 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -673,7 +673,7 @@ fn impl_block_datum( let bound_vars = Substs::bound_vars(&generic_params); let trait_ref = trait_ref.subst(&bound_vars); let trait_ = trait_ref.trait_; - let impl_type = if impl_id.lookup(db).container.krate == krate { + let impl_type = if impl_id.lookup(db).container.module(db).krate == krate { chalk_rust_ir::ImplType::Local } else { chalk_rust_ir::ImplType::External -- cgit v1.2.3 From 1b8ce5b37b597679796b3ebc57afd55af49449b0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 20 Dec 2019 15:58:20 +0100 Subject: Move impls to ItemScope --- crates/ra_hir_ty/src/method_resolution.rs | 2 +- crates/ra_hir_ty/src/test_db.rs | 2 +- crates/ra_hir_ty/src/tests.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 92fb4c081..888dc3116 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -58,7 +58,7 @@ impl CrateImplBlocks { let crate_def_map = db.crate_def_map(krate); for (_module_id, module_data) in crate_def_map.modules.iter() { - for &impl_id in module_data.impls.iter() { + for impl_id in module_data.scope.impls() { match db.impl_trait(impl_id) { Some(tr) => { res.impls_by_trait.entry(tr.trait_).or_default().push(impl_id); diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index 476f6df52..1a31b587b 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs @@ -98,7 +98,7 @@ impl TestDB { } } - for &impl_id in crate_def_map[module_id].impls.iter() { + for impl_id in crate_def_map[module_id].scope.impls() { let impl_data = self.impl_data(impl_id); for item in impl_data.items.iter() { if let AssocItemId::FunctionId(f) = item { diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index d724ee122..d447b4571 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -182,7 +182,7 @@ fn visit_module( _ => (), } } - for &impl_id in crate_def_map[module_id].impls.iter() { + for impl_id in crate_def_map[module_id].scope.impls() { let impl_data = db.impl_data(impl_id); for &item in impl_data.items.iter() { match item { -- cgit v1.2.3 From 2a8c9100bfb1294a469bc039a5b9597eabed7073 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 20 Dec 2019 16:41:32 +0100 Subject: Handle closure return types Fixes #2547. --- crates/ra_hir_ty/src/infer.rs | 7 ++++- crates/ra_hir_ty/src/infer/expr.rs | 17 +++++++++-- crates/ra_hir_ty/src/tests/coercion.rs | 31 +++++++++++++++++++ crates/ra_hir_ty/src/tests/simple.rs | 55 ++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index bbbc391c4..9f2ed830e 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -196,7 +196,12 @@ struct InferenceContext<'a, D: HirDatabase> { trait_env: Arc, obligations: Vec, result: InferenceResult, - /// The return type of the function being inferred. + /// The return type of the function being inferred, or the closure if we're + /// currently within one. + /// + /// We might consider using a nested inference context for checking + /// closures, but currently this is the only field that will change there, + /// so it doesn't make sense. return_ty: Ty, /// Impls of `CoerceUnsized` used in coercion. diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 8be567917..253332c30 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -102,7 +102,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.infer_expr(*body, &Expectation::has_type(Ty::unit())); Ty::unit() } - Expr::Lambda { body, args, arg_types } => { + Expr::Lambda { body, args, ret_type, arg_types } => { assert_eq!(args.len(), arg_types.len()); let mut sig_tys = Vec::new(); @@ -118,7 +118,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } // add return type - let ret_ty = self.table.new_type_var(); + let ret_ty = match ret_type { + Some(type_ref) => self.make_ty(type_ref), + None => self.table.new_type_var(), + }; sig_tys.push(ret_ty.clone()); let sig_ty = Ty::apply( TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, @@ -134,7 +137,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // infer the body. self.coerce(&closure_ty, &expected.ty); - self.infer_expr(*body, &Expectation::has_type(ret_ty)); + let prev_ret_ty = std::mem::replace(&mut self.return_ty, ret_ty.clone()); + + self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); + + self.return_ty = prev_ret_ty; + closure_ty } Expr::Call { callee, args } => { @@ -192,6 +200,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Expr::Return { expr } => { if let Some(expr) = expr { self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone())); + } else { + let unit = Ty::unit(); + self.coerce(&unit, &self.return_ty.clone()); } Ty::simple(TypeCtor::Never) } diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index ac9e3872a..33d6ca403 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -440,3 +440,34 @@ fn test() { "### ); } + +#[test] +fn closure_return_coerce() { + assert_snapshot!( + infer_with_mismatches(r#" +fn foo() { + let x = || { + if true { + return &1u32; + } + &&1u32 + }; +} +"#, true), + @r###" + [10; 106) '{ ... }; }': () + [20; 21) 'x': || -> &u32 + [24; 103) '|| { ... }': || -> &u32 + [27; 103) '{ ... }': &u32 + [37; 82) 'if tru... }': () + [40; 44) 'true': bool + [45; 82) '{ ... }': ! + [59; 71) 'return &1u32': ! + [66; 71) '&1u32': &u32 + [67; 71) '1u32': u32 + [91; 97) '&&1u32': &&u32 + [92; 97) '&1u32': &u32 + [93; 97) '1u32': u32 + "### + ); +} diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 18976c9ae..6fe647a5e 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -1606,3 +1606,58 @@ fn main() { ); assert_eq!(t, "u32"); } + +#[test] +fn closure_return() { + assert_snapshot!( + infer(r#" +fn foo() -> u32 { + let x = || -> usize { return 1; }; +} +"#), + @r###" + [17; 59) '{ ...; }; }': () + [27; 28) 'x': || -> usize + [31; 56) '|| -> ...n 1; }': || -> usize + [43; 56) '{ return 1; }': ! + [45; 53) 'return 1': ! + [52; 53) '1': usize + "### + ); +} + +#[test] +fn closure_return_unit() { + assert_snapshot!( + infer(r#" +fn foo() -> u32 { + let x = || { return; }; +} +"#), + @r###" + [17; 48) '{ ...; }; }': () + [27; 28) 'x': || -> () + [31; 45) '|| { return; }': || -> () + [34; 45) '{ return; }': ! + [36; 42) 'return': ! + "### + ); +} + +#[test] +fn closure_return_inferred() { + assert_snapshot!( + infer(r#" +fn foo() -> u32 { + let x = || { "test" }; +} +"#), + @r###" + [17; 47) '{ ..." }; }': () + [27; 28) 'x': || -> &str + [31; 44) '|| { "test" }': || -> &str + [34; 44) '{ "test" }': &str + [36; 42) '"test"': &str + "### + ); +} -- cgit v1.2.3 From 9c3f00a90651998c2cd4151f43f17cd92ef8eef1 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 20 Dec 2019 18:27:51 +0100 Subject: Fix coercion of last expression in function body --- crates/ra_hir_ty/src/infer.rs | 2 +- crates/ra_hir_ty/src/infer/expr.rs | 2 +- crates/ra_hir_ty/src/tests/coercion.rs | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 9f2ed830e..e97b81473 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -460,7 +460,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } fn infer_body(&mut self) { - self.infer_expr(self.body.body_expr, &Expectation::has_type(self.return_ty.clone())); + self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone())); } fn resolve_into_iter_item(&self) -> Option { diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 253332c30..3af05394c 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -41,7 +41,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { /// Infer type of expression with possibly implicit coerce to the expected type. /// Return the type after possible coercion. - fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { + pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { let ty = self.infer_expr_inner(expr, &expected); let ty = if !self.coerce(&ty, &expected.ty) { self.result diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 33d6ca403..793c23e41 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -369,6 +369,22 @@ fn test() { ); } +#[test] +fn return_coerce_unknown() { + assert_snapshot!( + infer_with_mismatches(r#" +fn foo() -> u32 { + return unknown; +} +"#, true), + @r###" + [17; 40) '{ ...own; }': ! + [23; 37) 'return unknown': ! + [30; 37) 'unknown': u32 + "### + ); +} + #[test] fn coerce_autoderef() { assert_snapshot!( -- cgit v1.2.3 From 44b00aed4a7d7e329fcbfa95a8685437cfb06e41 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 20 Dec 2019 18:53:40 +0100 Subject: Coerce closures to fn pointers E.g. `let x: fn(A) -> B = |x| { y };` --- crates/ra_hir_ty/src/infer/coerce.rs | 4 ++++ crates/ra_hir_ty/src/tests/coercion.rs | 39 ++++++++++++++++++++++++++++++++++ crates/ra_hir_ty/src/tests/traits.rs | 10 ++++----- 3 files changed, 48 insertions(+), 5 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 0f4dac45e..83c0c2c3f 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs @@ -134,6 +134,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } + (ty_app!(TypeCtor::Closure { .. }, params), ty_app!(TypeCtor::FnPtr { .. })) => { + from_ty = params[0].clone(); + } + _ => {} } diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 793c23e41..7e99a42ed 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -487,3 +487,42 @@ fn foo() { "### ); } + +#[test] +fn coerce_fn_item_to_fn_ptr() { + assert_snapshot!( + infer_with_mismatches(r#" +fn foo(x: u32) -> isize { 1 } +fn test() { + let f: fn(u32) -> isize = foo; +} +"#, true), + @r###" + [8; 9) 'x': u32 + [25; 30) '{ 1 }': isize + [27; 28) '1': isize + [41; 79) '{ ...foo; }': () + [51; 52) 'f': fn(u32) -> isize + [73; 76) 'foo': fn foo(u32) -> isize + "### + ); +} + +#[test] +fn coerce_closure_to_fn_ptr() { + assert_snapshot!( + infer_with_mismatches(r#" +fn test() { + let f: fn(u32) -> isize = |x| { 1 }; +} +"#, true), + @r###" + [11; 55) '{ ...1 }; }': () + [21; 22) 'f': fn(u32) -> isize + [43; 52) '|x| { 1 }': |u32| -> isize + [44; 45) 'x': u32 + [47; 52) '{ 1 }': isize + [49; 50) '1': isize + "### + ); +} diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 2d92a5eec..76e2198b6 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -393,11 +393,11 @@ fn test() -> u64 { [54; 55) 'a': S [58; 59) 'S': S(fn(u32) -> u64) -> S [58; 68) 'S(|i| 2*i)': S - [60; 67) '|i| 2*i': |i32| -> i32 - [61; 62) 'i': i32 - [64; 65) '2': i32 - [64; 67) '2*i': i32 - [66; 67) 'i': i32 + [60; 67) '|i| 2*i': |u32| -> u64 + [61; 62) 'i': u32 + [64; 65) '2': u32 + [64; 67) '2*i': u32 + [66; 67) 'i': u32 [78; 79) 'b': u64 [82; 83) 'a': S [82; 85) 'a.0': fn(u32) -> u64 -- cgit v1.2.3 From ad81d1dbc19803b5ccf1b230237642944edbff13 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 21 Dec 2019 03:37:03 +0800 Subject: Add support macros in impl blocks --- crates/ra_hir_ty/src/tests/macros.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 812f171db..7fdbf996f 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -182,6 +182,25 @@ fn test() { S.foo()<|>; } assert_eq!(t, "u128"); } +#[test] +fn infer_impl_items_generated_by_macros() { + let t = type_at( + r#" +//- /main.rs +macro_rules! m { + () => (fn foo(&self) -> u128 {0}) +} +struct S; +impl S { + m!(); +} + +fn test() { S.foo()<|>; } +"#, + ); + assert_eq!(t, "u128"); +} + #[test] fn infer_macro_with_dollar_crate_is_correct_in_expr() { let (db, pos) = TestDB::with_position( -- cgit v1.2.3 From 0d5d63a80ea08f2af439bcc72fff9b24d144c70d Mon Sep 17 00:00:00 2001 From: kjeremy Date: Fri, 20 Dec 2019 15:14:30 -0500 Subject: Clippy lints --- crates/ra_hir_ty/src/autoderef.rs | 4 ++-- crates/ra_hir_ty/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs index ee48fa537..f32d5786a 100644 --- a/crates/ra_hir_ty/src/autoderef.rs +++ b/crates/ra_hir_ty/src/autoderef.rs @@ -48,7 +48,7 @@ fn deref_by_trait( krate: CrateId, ty: InEnvironment<&Canonical>, ) -> Option> { - let deref_trait = match db.lang_item(krate.into(), "deref".into())? { + let deref_trait = match db.lang_item(krate, "deref".into())? { LangItemTarget::TraitId(it) => it, _ => return None, }; @@ -78,7 +78,7 @@ fn deref_by_trait( let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env }; - let solution = db.trait_solve(krate.into(), canonical)?; + let solution = db.trait_solve(krate, canonical)?; match &solution { Solution::Unique(vars) => { diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 7310ef10d..48abf97c9 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -919,7 +919,7 @@ impl HirDisplay for ApplicationTy { { Option::None => self.parameters.0.as_ref(), Option::Some(default_parameters) => { - for (i, parameter) in self.parameters.into_iter().enumerate() { + for (i, parameter) in self.parameters.iter().enumerate() { match (parameter, default_parameters.get(i)) { (&Ty::Unknown, _) | (_, None) => { non_default_parameters.push(parameter.clone()) -- cgit v1.2.3 From 360de5ba71a631a118a088dba7c975e9ae592452 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 21 Dec 2019 05:02:31 +0800 Subject: Recursive collect macros in impl items --- crates/ra_hir_ty/src/tests/macros.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 7fdbf996f..69c695cc8 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -201,6 +201,29 @@ fn test() { S.foo()<|>; } assert_eq!(t, "u128"); } +#[test] +fn infer_impl_items_generated_by_macros_chain() { + let t = type_at( + r#" +//- /main.rs +macro_rules! m_inner { + () => {fn foo(&self) -> u128 {0}} +} +macro_rules! m { + () => {m_inner!();} +} + +struct S; +impl S { + m!(); +} + +fn test() { S.foo()<|>; } +"#, + ); + assert_eq!(t, "u128"); +} + #[test] fn infer_macro_with_dollar_crate_is_correct_in_expr() { let (db, pos) = TestDB::with_position( -- cgit v1.2.3 From e424545c0f5cbaf135c52764169ea20df7d07d35 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 22 Dec 2019 20:12:23 +0100 Subject: Rudimentary name resolution for local items --- crates/ra_hir_ty/src/tests/simple.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 6fe647a5e..3e5e163e3 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -1512,8 +1512,8 @@ fn test() { [49; 50) '0': u32 [80; 83) '101': u32 [95; 213) '{ ...NST; }': () - [138; 139) 'x': {unknown} - [142; 153) 'LOCAL_CONST': {unknown} + [138; 139) 'x': u32 + [142; 153) 'LOCAL_CONST': u32 [163; 164) 'z': u32 [167; 179) 'GLOBAL_CONST': u32 [189; 191) 'id': u32 @@ -1541,10 +1541,10 @@ fn test() { [29; 32) '101': u32 [70; 73) '101': u32 [85; 280) '{ ...MUT; }': () - [173; 174) 'x': {unknown} - [177; 189) 'LOCAL_STATIC': {unknown} - [199; 200) 'y': {unknown} - [203; 219) 'LOCAL_...IC_MUT': {unknown} + [173; 174) 'x': u32 + [177; 189) 'LOCAL_STATIC': u32 + [199; 200) 'y': u32 + [203; 219) 'LOCAL_...IC_MUT': u32 [229; 230) 'z': u32 [233; 246) 'GLOBAL_STATIC': u32 [256; 257) 'w': u32 -- cgit v1.2.3 From 67a2555f6d4c3914742fd42645ca043cf56f358b Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 21 Dec 2019 14:29:33 +0100 Subject: Update Chalk, clean up Chalk integration a bit --- crates/ra_hir_ty/Cargo.toml | 7 +- crates/ra_hir_ty/src/db.rs | 35 ++----- crates/ra_hir_ty/src/traits.rs | 6 +- crates/ra_hir_ty/src/traits/chalk.rs | 180 +++++++++++++++++------------------ 4 files changed, 103 insertions(+), 125 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index d277bf2bc..60793db44 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml @@ -21,10 +21,9 @@ ra_prof = { path = "../ra_prof" } ra_syntax = { path = "../ra_syntax" } test_utils = { path = "../test_utils" } -# https://github.com/rust-lang/chalk/pull/294 -chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "151949dece8117d180b5d197a7afa968c3ba14bb" } -chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "151949dece8117d180b5d197a7afa968c3ba14bb" } -chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "151949dece8117d180b5d197a7afa968c3ba14bb" } +chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5" } +chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5" } +chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5" } lalrpop-intern = "0.15.1" diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index 222a36a9f..d52f65b83 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs @@ -10,7 +10,7 @@ use ra_db::{salsa, CrateId}; use crate::{ method_resolution::CrateImplBlocks, - traits::{AssocTyValue, Impl}, + traits::{chalk, AssocTyValue, Impl}, CallableDef, FnSig, GenericPredicate, InferenceResult, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, }; @@ -77,39 +77,24 @@ pub trait HirDatabase: DefDatabase { #[salsa::interned] fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId; - #[salsa::invoke(crate::traits::chalk::associated_ty_data_query)] - fn associated_ty_data( - &self, - id: chalk_ir::TypeId, - ) -> Arc>; + #[salsa::invoke(chalk::associated_ty_data_query)] + fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc; - #[salsa::invoke(crate::traits::chalk::trait_datum_query)] - fn trait_datum( - &self, - krate: CrateId, - trait_id: chalk_ir::TraitId, - ) -> Arc>; + #[salsa::invoke(chalk::trait_datum_query)] + fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc; - #[salsa::invoke(crate::traits::chalk::struct_datum_query)] - fn struct_datum( - &self, - krate: CrateId, - struct_id: chalk_ir::StructId, - ) -> Arc>; + #[salsa::invoke(chalk::struct_datum_query)] + fn struct_datum(&self, krate: CrateId, struct_id: chalk::StructId) -> Arc; #[salsa::invoke(crate::traits::chalk::impl_datum_query)] - fn impl_datum( - &self, - krate: CrateId, - impl_id: chalk_ir::ImplId, - ) -> Arc>; + fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc; #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] fn associated_ty_value( &self, krate: CrateId, - id: chalk_rust_ir::AssociatedTyValueId, - ) -> Arc>; + id: chalk::AssociatedTyValueId, + ) -> Arc; #[salsa::invoke(crate::traits::trait_solve_query)] fn trait_solve( diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index d49f8fb4b..46e17f0b8 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs @@ -209,9 +209,9 @@ fn solution_from_chalk( .parameters .into_iter() .map(|p| { - let ty = match p { - chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty), - chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(), + let ty = match p.ty() { + Some(ty) => from_chalk(db, ty.clone()), + None => unimplemented!(), }; ty }) diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 5eb032d86..3a91a374d 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -3,15 +3,9 @@ use std::sync::Arc; use log::debug; -use chalk_ir::{ - cast::Cast, family::ChalkIr, Identifier, Parameter, PlaceholderIndex, TypeId, TypeKindId, - TypeName, UniverseIndex, -}; -use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; +use chalk_ir::{cast::Cast, family::ChalkIr, Parameter, PlaceholderIndex, TypeName, UniverseIndex}; -use hir_def::{ - AssocContainerId, AssocItemId, GenericDefId, HasModule, ImplId, Lookup, TraitId, TypeAliasId, -}; +use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId}; use ra_db::{ salsa::{InternId, InternKey}, CrateId, @@ -23,9 +17,20 @@ use crate::{ ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }; +pub type TypeFamily = chalk_ir::family::ChalkIr; // TODO use everywhere +pub type AssocTypeId = chalk_ir::AssocTypeId; +pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum; +pub type TraitId = chalk_ir::TraitId; +pub type TraitDatum = chalk_rust_ir::TraitDatum; +pub type StructId = chalk_ir::StructId; +pub type StructDatum = chalk_rust_ir::StructDatum; +pub type ImplId = chalk_ir::ImplId; +pub type ImplDatum = chalk_rust_ir::ImplDatum; +pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId; +pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue; + /// This represents a trait whose name we could not resolve. -const UNKNOWN_TRAIT: chalk_ir::TraitId = - chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() }); +const UNKNOWN_TRAIT: TraitId = chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() }); pub(super) trait ToChalk { type Chalk; @@ -53,7 +58,7 @@ impl ToChalk for Ty { _ => { // other TypeCtors get interned and turned into a chalk StructId let struct_id = apply_ty.ctor.to_chalk(db); - TypeName::TypeKindId(struct_id.into()) + TypeName::Struct(struct_id.into()) } }; let parameters = apply_ty.parameters.to_chalk(db); @@ -71,11 +76,13 @@ impl ToChalk for Ty { Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), Ty::Dyn(predicates) => { let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect(); - chalk_ir::TyData::Dyn(make_binders(where_clauses, 1)).intern() + let bounded_ty = chalk_ir::BoundedTy { bounds: make_binders(where_clauses, 1) }; + chalk_ir::TyData::Dyn(bounded_ty).intern() } Ty::Opaque(predicates) => { let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect(); - chalk_ir::TyData::Opaque(make_binders(where_clauses, 1)).intern() + let bounded_ty = chalk_ir::BoundedTy { bounds: make_binders(where_clauses, 1) }; + chalk_ir::TyData::Opaque(bounded_ty).intern() } Ty::Unknown => { let parameters = Vec::new(); @@ -87,10 +94,9 @@ impl ToChalk for Ty { fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { match chalk.data().clone() { chalk_ir::TyData::Apply(apply_ty) => { - // FIXME this is kind of hacky due to the fact that - // TypeName::Placeholder is a Ty::Param on our side + // TODO clean this up now that Placeholder isn't in TypeName anymore match apply_ty.name { - TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => { + TypeName::Struct(struct_id) => { let ctor = from_chalk(db, struct_id); let parameters = from_chalk(db, apply_ty.parameters); Ty::Apply(ApplicationTy { ctor, parameters }) @@ -101,14 +107,12 @@ impl ToChalk for Ty { Ty::Apply(ApplicationTy { ctor, parameters }) } TypeName::Error => Ty::Unknown, - // FIXME handle TypeKindId::Trait/Type here - TypeName::TypeKindId(_) => unimplemented!(), - TypeName::Placeholder(idx) => { - assert_eq!(idx.ui, UniverseIndex::ROOT); - Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } - } } } + chalk_ir::TyData::Placeholder(idx) => { + assert_eq!(idx.ui, UniverseIndex::ROOT); + Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } + } chalk_ir::TyData::Projection(proj) => { let associated_ty = from_chalk(db, proj.associated_ty_id); let parameters = from_chalk(db, proj.parameters); @@ -118,15 +122,15 @@ impl ToChalk for Ty { chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx as u32), chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, chalk_ir::TyData::Dyn(where_clauses) => { - assert_eq!(where_clauses.binders.len(), 1); + assert_eq!(where_clauses.bounds.binders.len(), 1); let predicates = - where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); + where_clauses.bounds.value.into_iter().map(|c| from_chalk(db, c)).collect(); Ty::Dyn(predicates) } chalk_ir::TyData::Opaque(where_clauses) => { - assert_eq!(where_clauses.binders.len(), 1); + assert_eq!(where_clauses.bounds.binders.len(), 1); let predicates = - where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); + where_clauses.bounds.value.into_iter().map(|c| from_chalk(db, c)).collect(); Ty::Opaque(predicates) } } @@ -143,9 +147,9 @@ impl ToChalk for Substs { fn from_chalk(db: &impl HirDatabase, parameters: Vec>) -> Substs { let tys = parameters .into_iter() - .map(|p| match p { - chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty), - chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(), + .map(|p| match p.ty() { + Some(ty) => from_chalk(db, ty.clone()), + None => unimplemented!(), }) .collect(); Substs(tys) @@ -168,65 +172,62 @@ impl ToChalk for TraitRef { } } -impl ToChalk for TraitId { - type Chalk = chalk_ir::TraitId; +impl ToChalk for hir_def::TraitId { + type Chalk = TraitId; - fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId { + fn to_chalk(self, _db: &impl HirDatabase) -> TraitId { chalk_ir::TraitId(id_to_chalk(self)) } - fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> TraitId { + fn from_chalk(_db: &impl HirDatabase, trait_id: TraitId) -> hir_def::TraitId { id_from_chalk(trait_id.0) } } impl ToChalk for TypeCtor { - type Chalk = chalk_ir::StructId; + type Chalk = StructId; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::StructId { + fn to_chalk(self, db: &impl HirDatabase) -> StructId { db.intern_type_ctor(self).into() } - fn from_chalk(db: &impl HirDatabase, struct_id: chalk_ir::StructId) -> TypeCtor { + fn from_chalk(db: &impl HirDatabase, struct_id: StructId) -> TypeCtor { db.lookup_intern_type_ctor(struct_id.into()) } } impl ToChalk for Impl { - type Chalk = chalk_ir::ImplId; + type Chalk = ImplId; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { + fn to_chalk(self, db: &impl HirDatabase) -> ImplId { db.intern_chalk_impl(self).into() } - fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl { + fn from_chalk(db: &impl HirDatabase, impl_id: ImplId) -> Impl { db.lookup_intern_chalk_impl(impl_id.into()) } } impl ToChalk for TypeAliasId { - type Chalk = chalk_ir::TypeId; + type Chalk = AssocTypeId; - fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TypeId { - chalk_ir::TypeId(id_to_chalk(self)) + fn to_chalk(self, _db: &impl HirDatabase) -> AssocTypeId { + chalk_ir::AssocTypeId(id_to_chalk(self)) } - fn from_chalk(_db: &impl HirDatabase, type_alias_id: chalk_ir::TypeId) -> TypeAliasId { + fn from_chalk(_db: &impl HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId { id_from_chalk(type_alias_id.0) } } impl ToChalk for AssocTyValue { - type Chalk = chalk_rust_ir::AssociatedTyValueId; + type Chalk = AssociatedTyValueId; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::AssociatedTyValueId { + fn to_chalk(self, db: &impl HirDatabase) -> AssociatedTyValueId { db.intern_assoc_ty_value(self).into() } - fn from_chalk( - db: &impl HirDatabase, - assoc_ty_value_id: chalk_rust_ir::AssociatedTyValueId, - ) -> AssocTyValue { + fn from_chalk(db: &impl HirDatabase, assoc_ty_value_id: AssociatedTyValueId) -> AssocTyValue { db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into()) } } @@ -468,28 +469,28 @@ impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> where DB: HirDatabase, { - fn associated_ty_data(&self, id: TypeId) -> Arc> { + fn associated_ty_data(&self, id: AssocTypeId) -> Arc { self.db.associated_ty_data(id) } - fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc> { + fn trait_datum(&self, trait_id: TraitId) -> Arc { self.db.trait_datum(self.krate, trait_id) } - fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc> { + fn struct_datum(&self, struct_id: StructId) -> Arc { self.db.struct_datum(self.krate, struct_id) } - fn impl_datum(&self, impl_id: chalk_ir::ImplId) -> Arc> { + fn impl_datum(&self, impl_id: ImplId) -> Arc { self.db.impl_datum(self.krate, impl_id) } fn impls_for_trait( &self, - trait_id: chalk_ir::TraitId, - parameters: &[Parameter], - ) -> Vec { + trait_id: TraitId, + parameters: &[Parameter], + ) -> Vec { debug!("impls_for_trait {:?}", trait_id); if trait_id == UNKNOWN_TRAIT { return Vec::new(); } - let trait_: TraitId = from_chalk(self.db, trait_id); + let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); let mut result: Vec<_> = self .db .impls_for_trait(self.krate, trait_.into()) @@ -508,39 +509,32 @@ where debug!("impls_for_trait returned {} impls", result.len()); result } - fn impl_provided_for( - &self, - auto_trait_id: chalk_ir::TraitId, - struct_id: chalk_ir::StructId, - ) -> bool { + fn impl_provided_for(&self, auto_trait_id: TraitId, struct_id: StructId) -> bool { debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); false // FIXME } - fn type_name(&self, _id: TypeKindId) -> Identifier { - unimplemented!() - } - fn associated_ty_value( - &self, - id: chalk_rust_ir::AssociatedTyValueId, - ) -> Arc> { + fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc { self.db.associated_ty_value(self.krate.into(), id) } fn custom_clauses(&self) -> Vec> { vec![] } - fn local_impls_to_coherence_check( - &self, - _trait_id: chalk_ir::TraitId, - ) -> Vec { + fn local_impls_to_coherence_check(&self, _trait_id: TraitId) -> Vec { // We don't do coherence checking (yet) unimplemented!() } + fn as_struct_id(&self, id: &TypeName) -> Option { + match id { + TypeName::Struct(struct_id) => Some(*struct_id), + _ => None, + } + } } pub(crate) fn associated_ty_data_query( db: &impl HirDatabase, - id: TypeId, -) -> Arc> { + id: AssocTypeId, +) -> Arc { debug!("associated_ty_data {:?}", id); let type_alias: TypeAliasId = from_chalk(db, id); let trait_ = match type_alias.lookup(db).container { @@ -565,8 +559,8 @@ pub(crate) fn associated_ty_data_query( pub(crate) fn trait_datum_query( db: &impl HirDatabase, krate: CrateId, - trait_id: chalk_ir::TraitId, -) -> Arc> { + trait_id: TraitId, +) -> Arc { debug!("trait_datum {:?}", trait_id); if trait_id == UNKNOWN_TRAIT { let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses: Vec::new() }; @@ -586,7 +580,7 @@ pub(crate) fn trait_datum_query( associated_ty_ids: vec![], }); } - let trait_: TraitId = from_chalk(db, trait_id); + let trait_: hir_def::TraitId = from_chalk(db, trait_id); let trait_data = db.trait_data(trait_); debug!("trait {:?} = {:?}", trait_id, trait_data.name); let generic_params = generics(db, trait_.into()); @@ -616,8 +610,8 @@ pub(crate) fn trait_datum_query( pub(crate) fn struct_datum_query( db: &impl HirDatabase, krate: CrateId, - struct_id: chalk_ir::StructId, -) -> Arc> { + struct_id: StructId, +) -> Arc { debug!("struct_datum {:?}", struct_id); let type_ctor: TypeCtor = from_chalk(db, struct_id); debug!("struct {:?} = {:?}", struct_id, type_ctor); @@ -648,8 +642,8 @@ pub(crate) fn struct_datum_query( pub(crate) fn impl_datum_query( db: &impl HirDatabase, krate: CrateId, - impl_id: chalk_ir::ImplId, -) -> Arc> { + impl_id: ImplId, +) -> Arc { let _p = ra_prof::profile("impl_datum"); debug!("impl_datum {:?}", impl_id); let impl_: Impl = from_chalk(db, impl_id); @@ -663,9 +657,9 @@ pub(crate) fn impl_datum_query( fn impl_block_datum( db: &impl HirDatabase, krate: CrateId, - chalk_id: chalk_ir::ImplId, - impl_id: ImplId, -) -> Option>> { + chalk_id: ImplId, + impl_id: hir_def::ImplId, +) -> Option> { let trait_ref = db.impl_trait(impl_id)?; let impl_data = db.impl_data(impl_id); @@ -721,7 +715,7 @@ fn impl_block_datum( Some(Arc::new(impl_datum)) } -fn invalid_impl_datum() -> Arc> { +fn invalid_impl_datum() -> Arc { let trait_ref = chalk_ir::TraitRef { trait_id: UNKNOWN_TRAIT, parameters: vec![chalk_ir::TyData::BoundVar(0).cast().intern().cast()], @@ -754,7 +748,7 @@ fn type_alias_associated_ty_value( db: &impl HirDatabase, _krate: CrateId, type_alias: TypeAliasId, -) -> Arc> { +) -> Arc { let type_alias_data = db.type_alias_data(type_alias); let impl_id = match type_alias.lookup(db).container { AssocContainerId::ImplId(it) => it, @@ -786,25 +780,25 @@ fn id_to_chalk(salsa_id: T) -> chalk_ir::RawId { chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() } } -impl From for crate::TypeCtorId { - fn from(struct_id: chalk_ir::StructId) -> Self { +impl From for crate::TypeCtorId { + fn from(struct_id: StructId) -> Self { id_from_chalk(struct_id.0) } } -impl From for chalk_ir::StructId { +impl From for StructId { fn from(type_ctor_id: crate::TypeCtorId) -> Self { chalk_ir::StructId(id_to_chalk(type_ctor_id)) } } -impl From for crate::traits::GlobalImplId { - fn from(impl_id: chalk_ir::ImplId) -> Self { +impl From for crate::traits::GlobalImplId { + fn from(impl_id: ImplId) -> Self { id_from_chalk(impl_id.0) } } -impl From for chalk_ir::ImplId { +impl From for ImplId { fn from(impl_id: crate::traits::GlobalImplId) -> Self { chalk_ir::ImplId(id_to_chalk(impl_id)) } -- cgit v1.2.3 From 6b5efe5bdab160278469417734f4bb619c7bac61 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 21 Dec 2019 14:46:15 +0100 Subject: Refactor Chalk integration some more --- crates/ra_hir_ty/src/traits.rs | 14 ++-- crates/ra_hir_ty/src/traits/chalk.rs | 148 ++++++++++++++++++----------------- 2 files changed, 83 insertions(+), 79 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 46e17f0b8..fbab60925 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs @@ -1,7 +1,7 @@ //! Trait solving using Chalk. use std::sync::{Arc, Mutex}; -use chalk_ir::{cast::Cast, family::ChalkIr}; +use chalk_ir::cast::Cast; use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; use log::debug; use ra_db::{impl_intern_key, salsa, CrateId}; @@ -12,7 +12,7 @@ use crate::db::HirDatabase; use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; -use self::chalk::{from_chalk, ToChalk}; +use self::chalk::{from_chalk, ToChalk, TypeFamily}; pub(crate) mod chalk; mod builtin; @@ -20,7 +20,7 @@ mod builtin; #[derive(Debug, Clone)] pub struct TraitSolver { krate: CrateId, - inner: Arc>>, + inner: Arc>>, } /// We need eq for salsa @@ -36,8 +36,8 @@ impl TraitSolver { fn solve( &self, db: &impl HirDatabase, - goal: &chalk_ir::UCanonical>>, - ) -> Option> { + goal: &chalk_ir::UCanonical>>, + ) -> Option> { let context = ChalkContext { db, krate: self.krate }; debug!("solve goal: {:?}", goal); let mut solver = match self.inner.lock() { @@ -201,9 +201,9 @@ pub(crate) fn trait_solve_query( fn solution_from_chalk( db: &impl HirDatabase, - solution: chalk_solve::Solution, + solution: chalk_solve::Solution, ) -> Solution { - let convert_subst = |subst: chalk_ir::Canonical>| { + let convert_subst = |subst: chalk_ir::Canonical>| { let value = subst .value .parameters diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 3a91a374d..d53d3fdeb 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use log::debug; -use chalk_ir::{cast::Cast, family::ChalkIr, Parameter, PlaceholderIndex, TypeName, UniverseIndex}; +use chalk_ir::{cast::Cast, Parameter, PlaceholderIndex, TypeName, UniverseIndex}; use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId}; use ra_db::{ @@ -17,7 +17,7 @@ use crate::{ ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }; -pub type TypeFamily = chalk_ir::family::ChalkIr; // TODO use everywhere +pub type TypeFamily = chalk_ir::family::ChalkIr; pub type AssocTypeId = chalk_ir::AssocTypeId; pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum; pub type TraitId = chalk_ir::TraitId; @@ -46,21 +46,11 @@ where } impl ToChalk for Ty { - type Chalk = chalk_ir::Ty; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { + type Chalk = chalk_ir::Ty; + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { match self { Ty::Apply(apply_ty) => { - let name = match apply_ty.ctor { - TypeCtor::AssociatedType(type_alias) => { - let type_id = type_alias.to_chalk(db); - TypeName::AssociatedType(type_id) - } - _ => { - // other TypeCtors get interned and turned into a chalk StructId - let struct_id = apply_ty.ctor.to_chalk(db); - TypeName::Struct(struct_id.into()) - } - }; + let name = apply_ty.ctor.to_chalk(db); let parameters = apply_ty.parameters.to_chalk(db); chalk_ir::ApplicationTy { name, parameters }.cast().intern() } @@ -70,7 +60,8 @@ impl ToChalk for Ty { chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast().intern() } Ty::Param { idx, .. } => { - PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty::() + PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize } + .to_ty::() } Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(), Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), @@ -91,24 +82,16 @@ impl ToChalk for Ty { } } } - fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { + fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { match chalk.data().clone() { - chalk_ir::TyData::Apply(apply_ty) => { - // TODO clean this up now that Placeholder isn't in TypeName anymore - match apply_ty.name { - TypeName::Struct(struct_id) => { - let ctor = from_chalk(db, struct_id); - let parameters = from_chalk(db, apply_ty.parameters); - Ty::Apply(ApplicationTy { ctor, parameters }) - } - TypeName::AssociatedType(type_id) => { - let ctor = TypeCtor::AssociatedType(from_chalk(db, type_id)); - let parameters = from_chalk(db, apply_ty.parameters); - Ty::Apply(ApplicationTy { ctor, parameters }) - } - TypeName::Error => Ty::Unknown, + chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name { + TypeName::Error => Ty::Unknown, + _ => { + let ctor = from_chalk(db, apply_ty.name); + let parameters = from_chalk(db, apply_ty.parameters); + Ty::Apply(ApplicationTy { ctor, parameters }) } - } + }, chalk_ir::TyData::Placeholder(idx) => { assert_eq!(idx.ui, UniverseIndex::ROOT); Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } @@ -138,13 +121,16 @@ impl ToChalk for Ty { } impl ToChalk for Substs { - type Chalk = Vec>; + type Chalk = Vec>; - fn to_chalk(self, db: &impl HirDatabase) -> Vec> { + fn to_chalk(self, db: &impl HirDatabase) -> Vec> { self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect() } - fn from_chalk(db: &impl HirDatabase, parameters: Vec>) -> Substs { + fn from_chalk( + db: &impl HirDatabase, + parameters: Vec>, + ) -> Substs { let tys = parameters .into_iter() .map(|p| match p.ty() { @@ -157,15 +143,15 @@ impl ToChalk for Substs { } impl ToChalk for TraitRef { - type Chalk = chalk_ir::TraitRef; + type Chalk = chalk_ir::TraitRef; - fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef { + fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef { let trait_id = self.trait_.to_chalk(db); let parameters = self.substs.to_chalk(db); chalk_ir::TraitRef { trait_id, parameters } } - fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self { + fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self { let trait_ = from_chalk(db, trait_ref.trait_id); let substs = from_chalk(db, trait_ref.parameters); TraitRef { trait_, substs } @@ -185,14 +171,31 @@ impl ToChalk for hir_def::TraitId { } impl ToChalk for TypeCtor { - type Chalk = StructId; + type Chalk = TypeName; - fn to_chalk(self, db: &impl HirDatabase) -> StructId { - db.intern_type_ctor(self).into() + fn to_chalk(self, db: &impl HirDatabase) -> TypeName { + match self { + TypeCtor::AssociatedType(type_alias) => { + let type_id = type_alias.to_chalk(db); + TypeName::AssociatedType(type_id) + } + _ => { + // other TypeCtors get interned and turned into a chalk StructId + let struct_id = db.intern_type_ctor(self).into(); + TypeName::Struct(struct_id) + } + } } - fn from_chalk(db: &impl HirDatabase, struct_id: StructId) -> TypeCtor { - db.lookup_intern_type_ctor(struct_id.into()) + fn from_chalk(db: &impl HirDatabase, type_name: TypeName) -> TypeCtor { + match type_name { + TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), + TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), + TypeName::Error => { + // this should not be reached, since we don't represent TypeName::Error with TypeCtor + unreachable!() + } + } } } @@ -233,9 +236,9 @@ impl ToChalk for AssocTyValue { } impl ToChalk for GenericPredicate { - type Chalk = chalk_ir::QuantifiedWhereClause; + type Chalk = chalk_ir::QuantifiedWhereClause; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause { match self { GenericPredicate::Implemented(trait_ref) => { make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) @@ -259,7 +262,7 @@ impl ToChalk for GenericPredicate { fn from_chalk( db: &impl HirDatabase, - where_clause: chalk_ir::QuantifiedWhereClause, + where_clause: chalk_ir::QuantifiedWhereClause, ) -> GenericPredicate { match where_clause.value { chalk_ir::WhereClause::Implemented(tr) => { @@ -279,9 +282,9 @@ impl ToChalk for GenericPredicate { } impl ToChalk for ProjectionTy { - type Chalk = chalk_ir::ProjectionTy; + type Chalk = chalk_ir::ProjectionTy; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy { chalk_ir::ProjectionTy { associated_ty_id: self.associated_ty.to_chalk(db), parameters: self.parameters.to_chalk(db), @@ -290,7 +293,7 @@ impl ToChalk for ProjectionTy { fn from_chalk( db: &impl HirDatabase, - projection_ty: chalk_ir::ProjectionTy, + projection_ty: chalk_ir::ProjectionTy, ) -> ProjectionTy { ProjectionTy { associated_ty: from_chalk(db, projection_ty.associated_ty_id), @@ -300,31 +303,31 @@ impl ToChalk for ProjectionTy { } impl ToChalk for super::ProjectionPredicate { - type Chalk = chalk_ir::Normalize; + type Chalk = chalk_ir::Normalize; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize { chalk_ir::Normalize { projection: self.projection_ty.to_chalk(db), ty: self.ty.to_chalk(db), } } - fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize) -> Self { + fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize) -> Self { unimplemented!() } } impl ToChalk for Obligation { - type Chalk = chalk_ir::DomainGoal; + type Chalk = chalk_ir::DomainGoal; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal { match self { Obligation::Trait(tr) => tr.to_chalk(db).cast(), Obligation::Projection(pr) => pr.to_chalk(db).cast(), } } - fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal) -> Self { + fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal) -> Self { unimplemented!() } } @@ -348,16 +351,17 @@ where } impl ToChalk for Arc { - type Chalk = chalk_ir::Environment; + type Chalk = chalk_ir::Environment; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment { let mut clauses = Vec::new(); for pred in &self.predicates { if pred.is_error() { // for env, we just ignore errors continue; } - let program_clause: chalk_ir::ProgramClause = pred.clone().to_chalk(db).cast(); + let program_clause: chalk_ir::ProgramClause = + pred.clone().to_chalk(db).cast(); clauses.push(program_clause.into_from_env_clause()); } chalk_ir::Environment::new().add_clauses(clauses) @@ -365,7 +369,7 @@ impl ToChalk for Arc { fn from_chalk( _db: &impl HirDatabase, - _env: chalk_ir::Environment, + _env: chalk_ir::Environment, ) -> Arc { unimplemented!() } @@ -373,7 +377,7 @@ impl ToChalk for Arc { impl ToChalk for super::InEnvironment where - T::Chalk: chalk_ir::family::HasTypeFamily, + T::Chalk: chalk_ir::family::HasTypeFamily, { type Chalk = chalk_ir::InEnvironment; @@ -396,9 +400,9 @@ where } impl ToChalk for builtin::BuiltinImplData { - type Chalk = chalk_rust_ir::ImplDatum; + type Chalk = ImplDatum; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::ImplDatum { + fn to_chalk(self, db: &impl HirDatabase) -> ImplDatum { let impl_type = chalk_rust_ir::ImplType::External; let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect(); @@ -414,15 +418,15 @@ impl ToChalk for builtin::BuiltinImplData { } } - fn from_chalk(_db: &impl HirDatabase, _data: chalk_rust_ir::ImplDatum) -> Self { + fn from_chalk(_db: &impl HirDatabase, _data: ImplDatum) -> Self { unimplemented!() } } impl ToChalk for builtin::BuiltinImplAssocTyValueData { - type Chalk = chalk_rust_ir::AssociatedTyValue; + type Chalk = AssociatedTyValue; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::AssociatedTyValue { + fn to_chalk(self, db: &impl HirDatabase) -> AssociatedTyValue { let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: self.value.to_chalk(db) }; chalk_rust_ir::AssociatedTyValue { @@ -434,7 +438,7 @@ impl ToChalk for builtin::BuiltinImplAssocTyValueData { fn from_chalk( _db: &impl HirDatabase, - _data: chalk_rust_ir::AssociatedTyValue, + _data: AssociatedTyValue, ) -> builtin::BuiltinImplAssocTyValueData { unimplemented!() } @@ -451,7 +455,7 @@ fn convert_where_clauses( db: &impl HirDatabase, def: GenericDefId, substs: &Substs, -) -> Vec> { +) -> Vec> { let generic_predicates = db.generic_predicates(def); let mut result = Vec::with_capacity(generic_predicates.len()); for pred in generic_predicates.iter() { @@ -465,7 +469,7 @@ fn convert_where_clauses( result } -impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> +impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> where DB: HirDatabase, { @@ -516,7 +520,7 @@ where fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc { self.db.associated_ty_value(self.krate.into(), id) } - fn custom_clauses(&self) -> Vec> { + fn custom_clauses(&self) -> Vec> { vec![] } fn local_impls_to_coherence_check(&self, _trait_id: TraitId) -> Vec { @@ -613,7 +617,7 @@ pub(crate) fn struct_datum_query( struct_id: StructId, ) -> Arc { debug!("struct_datum {:?}", struct_id); - let type_ctor: TypeCtor = from_chalk(db, struct_id); + let type_ctor: TypeCtor = from_chalk(db, TypeName::Struct(struct_id)); debug!("struct {:?} = {:?}", struct_id, type_ctor); let num_params = type_ctor.num_ty_params(db); let upstream = type_ctor.krate(db) != Some(krate); @@ -733,8 +737,8 @@ fn invalid_impl_datum() -> Arc { pub(crate) fn associated_ty_value_query( db: &impl HirDatabase, krate: CrateId, - id: chalk_rust_ir::AssociatedTyValueId, -) -> Arc> { + id: AssociatedTyValueId, +) -> Arc { let data: AssocTyValue = from_chalk(db, id); match data { AssocTyValue::TypeAlias(type_alias) => { -- cgit v1.2.3 From 4053fcfca0e33f133c53fa755c1b1bcc0b4c11bb Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 21 Dec 2019 15:00:44 +0100 Subject: Introduce our own Chalk TypeFamily, instead of using ChalkIr It's not very different, except we can directly use Salsa IDs instead of casting them. This means we need to refactor the handling of errors to get rid of UNKNOWN_TRAIT though. --- crates/ra_hir_ty/src/tests/method_resolution.rs | 4 +- crates/ra_hir_ty/src/traits.rs | 4 +- crates/ra_hir_ty/src/traits/builtin.rs | 49 +++++--- crates/ra_hir_ty/src/traits/chalk.rs | 156 ++++++++++++++---------- 4 files changed, 126 insertions(+), 87 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 45164c9e9..ce9a06fde 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs @@ -865,7 +865,7 @@ mod foo { #[test] fn method_resolution_where_clause_for_unknown_trait() { - // The blanket impl shouldn't apply because we can't even resolve UnknownTrait + // The blanket impl currently applies because we ignore the unresolved where clause let t = type_at( r#" //- /main.rs @@ -875,7 +875,7 @@ impl Trait for T where T: UnknownTrait {} fn test() { (&S).foo()<|>; } "#, ); - assert_eq!(t, "{unknown}"); + assert_eq!(t, "u128"); } #[test] diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index fbab60925..c4dc857bc 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs @@ -291,7 +291,7 @@ impl FnTrait { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ClosureFnTraitImplData { def: DefWithBodyId, expr: ExprId, @@ -300,7 +300,7 @@ pub struct ClosureFnTraitImplData { /// An impl. Usually this comes from an impl block, but some built-in types get /// synthetic impls. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Impl { /// A normal impl from an impl block. ImplBlock(ImplId), diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index cd587a338..dd41176f0 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs @@ -28,24 +28,24 @@ pub(super) fn get_builtin_impls( trait_: TraitId, mut callback: impl FnMut(Impl), ) { + // Note: since impl_datum needs to be infallible, we need to make sure here + // that we have all prerequisites to build the respective impls. if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() { if let Some(actual_trait) = get_fn_trait(db, krate, fn_trait) { if trait_ == actual_trait { let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait }; - callback(Impl::ClosureFnTraitImpl(impl_)); + if check_closure_fn_trait_impl_prerequisites(db, krate, impl_) { + callback(Impl::ClosureFnTraitImpl(impl_)); + } } } } } } -pub(super) fn impl_datum( - db: &impl HirDatabase, - krate: CrateId, - impl_: Impl, -) -> Option { +pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { match impl_ { Impl::ImplBlock(_) => unreachable!(), Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), @@ -65,21 +65,38 @@ pub(super) fn associated_ty_value( } } +fn check_closure_fn_trait_impl_prerequisites( + db: &impl HirDatabase, + krate: CrateId, + data: super::ClosureFnTraitImplData, +) -> bool { + // the respective Fn/FnOnce/FnMut trait needs to exist + if get_fn_trait(db, krate, data.fn_trait).is_none() { + return false; + } + + // FIXME: there are more assumptions that we should probably check here: + // the traits having no type params, FnOnce being a supertrait + + // the FnOnce trait needs to exist and have an assoc type named Output + let fn_once_trait = match get_fn_trait(db, krate, super::FnTrait::FnOnce) { + Some(t) => t, + None => return false, + }; + db.trait_data(fn_once_trait).associated_type_by_name(&name![Output]).is_some() +} + fn closure_fn_trait_impl_datum( db: &impl HirDatabase, krate: CrateId, data: super::ClosureFnTraitImplData, -) -> Option { +) -> BuiltinImplData { // for some closure |X, Y| -> Z: // impl Fn<(T, U)> for closure V> { Output = V } - let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait - - // validate FnOnce trait, since we need it in the assoc ty value definition - // and don't want to return a valid value only to find out later that FnOnce - // is broken - let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; - let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; + let trait_ = get_fn_trait(db, krate, data.fn_trait) // get corresponding fn trait + // the existence of the Fn trait has been checked before + .expect("fn trait for closure impl missing"); let num_args: u16 = match &db.body(data.def.into())[data.expr] { Expr::Lambda { args, .. } => args.len() as u16, @@ -107,12 +124,12 @@ fn closure_fn_trait_impl_datum( let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()); - Some(BuiltinImplData { + BuiltinImplData { num_vars: num_args as usize + 1, trait_ref, where_clauses: Vec::new(), assoc_ty_values: vec![output_ty_id], - }) + } } fn closure_fn_trait_output_assoc_ty_value( diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index d53d3fdeb..9e38337e5 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -1,5 +1,5 @@ //! Conversion code from/to Chalk. -use std::sync::Arc; +use std::{fmt, sync::Arc}; use log::debug; @@ -17,7 +17,73 @@ use crate::{ ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }; -pub type TypeFamily = chalk_ir::family::ChalkIr; +#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] +pub struct TypeFamily {} + +impl chalk_ir::family::TypeFamily for TypeFamily { + type InternedType = Box>; + type InternedLifetime = chalk_ir::LifetimeData; + type InternedParameter = chalk_ir::ParameterData; + type DefId = InternId; + + // FIXME: implement these + fn debug_struct_id( + _type_kind_id: chalk_ir::StructId, + _fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + + fn debug_trait_id( + _type_kind_id: chalk_ir::TraitId, + _fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + + fn debug_assoc_type_id( + _id: chalk_ir::AssocTypeId, + _fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + + fn debug_projection( + _projection: &chalk_ir::ProjectionTy, + _fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + + fn intern_ty(ty: chalk_ir::TyData) -> Box> { + Box::new(ty) + } + + fn ty_data(ty: &Box>) -> &chalk_ir::TyData { + ty + } + + fn intern_lifetime(lifetime: chalk_ir::LifetimeData) -> chalk_ir::LifetimeData { + lifetime + } + + fn lifetime_data(lifetime: &chalk_ir::LifetimeData) -> &chalk_ir::LifetimeData { + lifetime + } + + fn intern_parameter(parameter: chalk_ir::ParameterData) -> chalk_ir::ParameterData { + parameter + } + + fn parameter_data(parameter: &chalk_ir::ParameterData) -> &chalk_ir::ParameterData { + parameter + } +} + +impl chalk_ir::family::HasTypeFamily for TypeFamily { + type TypeFamily = Self; +} + pub type AssocTypeId = chalk_ir::AssocTypeId; pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum; pub type TraitId = chalk_ir::TraitId; @@ -29,9 +95,6 @@ pub type ImplDatum = chalk_rust_ir::ImplDatum; pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId; pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue; -/// This represents a trait whose name we could not resolve. -const UNKNOWN_TRAIT: TraitId = chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() }); - pub(super) trait ToChalk { type Chalk; fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk; @@ -162,11 +225,11 @@ impl ToChalk for hir_def::TraitId { type Chalk = TraitId; fn to_chalk(self, _db: &impl HirDatabase) -> TraitId { - chalk_ir::TraitId(id_to_chalk(self)) + chalk_ir::TraitId(self.as_intern_id()) } fn from_chalk(_db: &impl HirDatabase, trait_id: TraitId) -> hir_def::TraitId { - id_from_chalk(trait_id.0) + InternKey::from_intern_id(trait_id.0) } } @@ -215,11 +278,11 @@ impl ToChalk for TypeAliasId { type Chalk = AssocTypeId; fn to_chalk(self, _db: &impl HirDatabase) -> AssocTypeId { - chalk_ir::AssocTypeId(id_to_chalk(self)) + chalk_ir::AssocTypeId(self.as_intern_id()) } fn from_chalk(_db: &impl HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId { - id_from_chalk(type_alias_id.0) + InternKey::from_intern_id(type_alias_id.0) } } @@ -250,13 +313,7 @@ impl ToChalk for GenericPredicate { }), 0, ), - GenericPredicate::Error => { - let impossible_trait_ref = chalk_ir::TraitRef { - trait_id: UNKNOWN_TRAIT, - parameters: vec![Ty::Unknown.to_chalk(db).cast()], - }; - make_binders(chalk_ir::WhereClause::Implemented(impossible_trait_ref), 0) - } + GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), } } @@ -266,10 +323,6 @@ impl ToChalk for GenericPredicate { ) -> GenericPredicate { match where_clause.value { chalk_ir::WhereClause::Implemented(tr) => { - if tr.trait_id == UNKNOWN_TRAIT { - // FIXME we need an Error enum on the Chalk side to avoid this - return GenericPredicate::Error; - } GenericPredicate::Implemented(from_chalk(db, tr)) } chalk_ir::WhereClause::ProjectionEq(projection_eq) => { @@ -460,9 +513,8 @@ fn convert_where_clauses( let mut result = Vec::with_capacity(generic_predicates.len()); for pred in generic_predicates.iter() { if pred.is_error() { - // HACK: Return just the single predicate (which is always false - // anyway), otherwise Chalk can easily get into slow situations - return vec![pred.clone().subst(substs).to_chalk(db)]; + // skip errored predicates completely + continue; } result.push(pred.clone().subst(substs).to_chalk(db)); } @@ -491,10 +543,11 @@ where parameters: &[Parameter], ) -> Vec { debug!("impls_for_trait {:?}", trait_id); - if trait_id == UNKNOWN_TRAIT { - return Vec::new(); - } let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); + + // Note: Since we're using impls_for_trait, only impls where the trait + // can be resolved should ever reach Chalk. `impl_datum` relies on that + // and will panic if the trait can't be resolved. let mut result: Vec<_> = self .db .impls_for_trait(self.krate, trait_.into()) @@ -566,24 +619,6 @@ pub(crate) fn trait_datum_query( trait_id: TraitId, ) -> Arc { debug!("trait_datum {:?}", trait_id); - if trait_id == UNKNOWN_TRAIT { - let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses: Vec::new() }; - - let flags = chalk_rust_ir::TraitFlags { - auto: false, - marker: false, - upstream: true, - fundamental: false, - non_enumerable: true, - coinductive: false, - }; - return Arc::new(TraitDatum { - id: trait_id, - binders: make_binders(trait_datum_bound, 1), - flags, - associated_ty_ids: vec![], - }); - } let trait_: hir_def::TraitId = from_chalk(db, trait_id); let trait_data = db.trait_data(trait_); debug!("trait {:?} = {:?}", trait_id, trait_data.name); @@ -653,9 +688,8 @@ pub(crate) fn impl_datum_query( let impl_: Impl = from_chalk(db, impl_id); match impl_ { Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block), - _ => builtin::impl_datum(db, krate, impl_).map(|d| Arc::new(d.to_chalk(db))), + _ => Arc::new(builtin::impl_datum(db, krate, impl_).to_chalk(db)), } - .unwrap_or_else(invalid_impl_datum) } fn impl_block_datum( @@ -663,8 +697,11 @@ fn impl_block_datum( krate: CrateId, chalk_id: ImplId, impl_id: hir_def::ImplId, -) -> Option> { - let trait_ref = db.impl_trait(impl_id)?; +) -> Arc { + let trait_ref = db + .impl_trait(impl_id) + // ImplIds for impls where the trait ref can't be resolved should never reach Chalk + .expect("invalid impl passed to Chalk"); let impl_data = db.impl_data(impl_id); let generic_params = generics(db, impl_id.into()); @@ -716,21 +753,6 @@ fn impl_block_datum( polarity, associated_ty_value_ids, }; - Some(Arc::new(impl_datum)) -} - -fn invalid_impl_datum() -> Arc { - let trait_ref = chalk_ir::TraitRef { - trait_id: UNKNOWN_TRAIT, - parameters: vec![chalk_ir::TyData::BoundVar(0).cast().intern().cast()], - }; - let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses: Vec::new() }; - let impl_datum = ImplDatum { - binders: make_binders(impl_datum_bound, 1), - impl_type: chalk_rust_ir::ImplType::External, - polarity: chalk_rust_ir::Polarity::Positive, - associated_ty_value_ids: Vec::new(), - }; Arc::new(impl_datum) } @@ -786,25 +808,25 @@ fn id_to_chalk(salsa_id: T) -> chalk_ir::RawId { impl From for crate::TypeCtorId { fn from(struct_id: StructId) -> Self { - id_from_chalk(struct_id.0) + InternKey::from_intern_id(struct_id.0) } } impl From for StructId { fn from(type_ctor_id: crate::TypeCtorId) -> Self { - chalk_ir::StructId(id_to_chalk(type_ctor_id)) + chalk_ir::StructId(type_ctor_id.as_intern_id()) } } impl From for crate::traits::GlobalImplId { fn from(impl_id: ImplId) -> Self { - id_from_chalk(impl_id.0) + InternKey::from_intern_id(impl_id.0) } } impl From for ImplId { fn from(impl_id: crate::traits::GlobalImplId) -> Self { - chalk_ir::ImplId(id_to_chalk(impl_id)) + chalk_ir::ImplId(impl_id.as_intern_id()) } } -- cgit v1.2.3 From 1f7f4578f72721c1b0e17e8405f986fd2ce89aaf Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 21 Dec 2019 19:15:06 +0100 Subject: Filter out error predicates in type bounds as well --- crates/ra_hir_ty/src/tests/traits.rs | 17 +++++++++++++++++ crates/ra_hir_ty/src/traits/chalk.rs | 14 ++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 76e2198b6..ae316922b 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -958,6 +958,23 @@ fn test() { ); } +#[test] +fn error_bound_chalk() { + let t = type_at( + r#" +//- /main.rs +trait Trait { + fn foo(&self) -> u32 {} +} + +fn test(x: (impl Trait + UnknownTrait)) { + x.foo()<|>; +} +"#, + ); + assert_eq!(t, "u32"); +} + #[test] fn assoc_type_bindings() { assert_snapshot!( diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 9e38337e5..555930c9b 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -129,12 +129,22 @@ impl ToChalk for Ty { Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(), Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), Ty::Dyn(predicates) => { - let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect(); + let where_clauses = predicates + .iter() + .filter(|p| !p.is_error()) + .cloned() + .map(|p| p.to_chalk(db)) + .collect(); let bounded_ty = chalk_ir::BoundedTy { bounds: make_binders(where_clauses, 1) }; chalk_ir::TyData::Dyn(bounded_ty).intern() } Ty::Opaque(predicates) => { - let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect(); + let where_clauses = predicates + .iter() + .filter(|p| !p.is_error()) + .cloned() + .map(|p| p.to_chalk(db)) + .collect(); let bounded_ty = chalk_ir::BoundedTy { bounds: make_binders(where_clauses, 1) }; chalk_ir::TyData::Opaque(bounded_ty).intern() } -- cgit v1.2.3