diff options
Diffstat (limited to 'crates/hir_ty')
36 files changed, 22908 insertions, 0 deletions
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml new file mode 100644 index 000000000..a319b0ce8 --- /dev/null +++ b/crates/hir_ty/Cargo.toml | |||
@@ -0,0 +1,37 @@ | |||
1 | [package] | ||
2 | name = "hir_ty" | ||
3 | version = "0.0.0" | ||
4 | license = "MIT OR Apache-2.0" | ||
5 | authors = ["rust-analyzer developers"] | ||
6 | edition = "2018" | ||
7 | |||
8 | [lib] | ||
9 | doctest = false | ||
10 | |||
11 | [dependencies] | ||
12 | itertools = "0.9.0" | ||
13 | arrayvec = "0.5.1" | ||
14 | smallvec = "1.2.0" | ||
15 | ena = "0.14.0" | ||
16 | log = "0.4.8" | ||
17 | rustc-hash = "1.1.0" | ||
18 | scoped-tls = "1" | ||
19 | chalk-solve = { version = "0.23.0" } | ||
20 | chalk-ir = { version = "0.23.0" } | ||
21 | chalk-recursive = { version = "0.23.0" } | ||
22 | |||
23 | stdx = { path = "../stdx" } | ||
24 | hir_def = { path = "../hir_def" } | ||
25 | hir_expand = { path = "../hir_expand" } | ||
26 | arena = { path = "../arena" } | ||
27 | base_db = { path = "../base_db" } | ||
28 | profile = { path = "../profile" } | ||
29 | syntax = { path = "../syntax" } | ||
30 | test_utils = { path = "../test_utils" } | ||
31 | |||
32 | [dev-dependencies] | ||
33 | tracing = "0.1" | ||
34 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } | ||
35 | tracing-tree = { version = "0.1.4" } | ||
36 | |||
37 | expect = { path = "../expect" } | ||
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs new file mode 100644 index 000000000..ece68183e --- /dev/null +++ b/crates/hir_ty/src/autoderef.rs | |||
@@ -0,0 +1,131 @@ | |||
1 | //! In certain situations, rust automatically inserts derefs as necessary: for | ||
2 | //! example, field accesses `foo.bar` still work when `foo` is actually a | ||
3 | //! reference to a type with the field `bar`. This is an approximation of the | ||
4 | //! logic in rustc (which lives in librustc_typeck/check/autoderef.rs). | ||
5 | |||
6 | use std::iter::successors; | ||
7 | |||
8 | use base_db::CrateId; | ||
9 | use hir_def::lang_item::LangItemTarget; | ||
10 | use hir_expand::name::name; | ||
11 | use log::{info, warn}; | ||
12 | |||
13 | use crate::{ | ||
14 | db::HirDatabase, | ||
15 | traits::{InEnvironment, Solution}, | ||
16 | utils::generics, | ||
17 | BoundVar, Canonical, DebruijnIndex, Obligation, Substs, TraitRef, Ty, | ||
18 | }; | ||
19 | |||
20 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | ||
21 | |||
22 | pub fn autoderef<'a>( | ||
23 | db: &'a dyn HirDatabase, | ||
24 | krate: Option<CrateId>, | ||
25 | ty: InEnvironment<Canonical<Ty>>, | ||
26 | ) -> impl Iterator<Item = Canonical<Ty>> + 'a { | ||
27 | let InEnvironment { value: ty, environment } = ty; | ||
28 | successors(Some(ty), move |ty| { | ||
29 | deref(db, krate?, InEnvironment { value: ty, environment: environment.clone() }) | ||
30 | }) | ||
31 | .take(AUTODEREF_RECURSION_LIMIT) | ||
32 | } | ||
33 | |||
34 | pub(crate) fn deref( | ||
35 | db: &dyn HirDatabase, | ||
36 | krate: CrateId, | ||
37 | ty: InEnvironment<&Canonical<Ty>>, | ||
38 | ) -> Option<Canonical<Ty>> { | ||
39 | if let Some(derefed) = ty.value.value.builtin_deref() { | ||
40 | Some(Canonical { value: derefed, kinds: ty.value.kinds.clone() }) | ||
41 | } else { | ||
42 | deref_by_trait(db, krate, ty) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | fn deref_by_trait( | ||
47 | db: &dyn HirDatabase, | ||
48 | krate: CrateId, | ||
49 | ty: InEnvironment<&Canonical<Ty>>, | ||
50 | ) -> Option<Canonical<Ty>> { | ||
51 | let deref_trait = match db.lang_item(krate, "deref".into())? { | ||
52 | LangItemTarget::TraitId(it) => it, | ||
53 | _ => return None, | ||
54 | }; | ||
55 | let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?; | ||
56 | |||
57 | let generic_params = generics(db.upcast(), target.into()); | ||
58 | if generic_params.len() != 1 { | ||
59 | // the Target type + Deref trait should only have one generic parameter, | ||
60 | // namely Deref's Self type | ||
61 | return None; | ||
62 | } | ||
63 | |||
64 | // FIXME make the Canonical / bound var handling nicer | ||
65 | |||
66 | let parameters = | ||
67 | Substs::build_for_generics(&generic_params).push(ty.value.value.clone()).build(); | ||
68 | |||
69 | // Check that the type implements Deref at all | ||
70 | let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() }; | ||
71 | let implements_goal = Canonical { | ||
72 | kinds: ty.value.kinds.clone(), | ||
73 | value: InEnvironment { | ||
74 | value: Obligation::Trait(trait_ref), | ||
75 | environment: ty.environment.clone(), | ||
76 | }, | ||
77 | }; | ||
78 | if db.trait_solve(krate, implements_goal).is_none() { | ||
79 | return None; | ||
80 | } | ||
81 | |||
82 | // Now do the assoc type projection | ||
83 | let projection = super::traits::ProjectionPredicate { | ||
84 | ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())), | ||
85 | projection_ty: super::ProjectionTy { associated_ty: target, parameters }, | ||
86 | }; | ||
87 | |||
88 | let obligation = super::Obligation::Projection(projection); | ||
89 | |||
90 | let in_env = InEnvironment { value: obligation, environment: ty.environment }; | ||
91 | |||
92 | let canonical = | ||
93 | Canonical::new(in_env, ty.value.kinds.iter().copied().chain(Some(super::TyKind::General))); | ||
94 | |||
95 | let solution = db.trait_solve(krate, canonical)?; | ||
96 | |||
97 | match &solution { | ||
98 | Solution::Unique(vars) => { | ||
99 | // FIXME: vars may contain solutions for any inference variables | ||
100 | // that happened to be inside ty. To correctly handle these, we | ||
101 | // would have to pass the solution up to the inference context, but | ||
102 | // that requires a larger refactoring (especially if the deref | ||
103 | // happens during method resolution). So for the moment, we just | ||
104 | // check that we're not in the situation we're we would actually | ||
105 | // need to handle the values of the additional variables, i.e. | ||
106 | // they're just being 'passed through'. In the 'standard' case where | ||
107 | // we have `impl<T> Deref for Foo<T> { Target = T }`, that should be | ||
108 | // the case. | ||
109 | |||
110 | // FIXME: if the trait solver decides to truncate the type, these | ||
111 | // assumptions will be broken. We would need to properly introduce | ||
112 | // new variables in that case | ||
113 | |||
114 | for i in 1..vars.0.kinds.len() { | ||
115 | if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) | ||
116 | { | ||
117 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); | ||
118 | return None; | ||
119 | } | ||
120 | } | ||
121 | Some(Canonical { | ||
122 | value: vars.0.value[vars.0.value.len() - 1].clone(), | ||
123 | kinds: vars.0.kinds.clone(), | ||
124 | }) | ||
125 | } | ||
126 | Solution::Ambig(_) => { | ||
127 | info!("Ambiguous solution for derefing {:?}: {:?}", ty.value, solution); | ||
128 | None | ||
129 | } | ||
130 | } | ||
131 | } | ||
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs new file mode 100644 index 000000000..25cf9eb7f --- /dev/null +++ b/crates/hir_ty/src/db.rs | |||
@@ -0,0 +1,158 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use arena::map::ArenaMap; | ||
6 | use base_db::{impl_intern_key, salsa, CrateId, Upcast}; | ||
7 | use hir_def::{ | ||
8 | db::DefDatabase, expr::ExprId, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, | ||
9 | TypeParamId, VariantId, | ||
10 | }; | ||
11 | |||
12 | use crate::{ | ||
13 | method_resolution::{InherentImpls, TraitImpls}, | ||
14 | traits::chalk, | ||
15 | Binders, CallableDefId, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, | ||
16 | ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId, | ||
17 | }; | ||
18 | use hir_expand::name::Name; | ||
19 | |||
20 | #[salsa::query_group(HirDatabaseStorage)] | ||
21 | pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | ||
22 | #[salsa::invoke(infer_wait)] | ||
23 | #[salsa::transparent] | ||
24 | fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>; | ||
25 | |||
26 | #[salsa::invoke(crate::infer::infer_query)] | ||
27 | fn infer_query(&self, def: DefWithBodyId) -> Arc<InferenceResult>; | ||
28 | |||
29 | #[salsa::invoke(crate::lower::ty_query)] | ||
30 | #[salsa::cycle(crate::lower::ty_recover)] | ||
31 | fn ty(&self, def: TyDefId) -> Binders<Ty>; | ||
32 | |||
33 | #[salsa::invoke(crate::lower::value_ty_query)] | ||
34 | fn value_ty(&self, def: ValueTyDefId) -> Binders<Ty>; | ||
35 | |||
36 | #[salsa::invoke(crate::lower::impl_self_ty_query)] | ||
37 | #[salsa::cycle(crate::lower::impl_self_ty_recover)] | ||
38 | fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>; | ||
39 | |||
40 | #[salsa::invoke(crate::lower::impl_trait_query)] | ||
41 | fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>; | ||
42 | |||
43 | #[salsa::invoke(crate::lower::field_types_query)] | ||
44 | fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>; | ||
45 | |||
46 | #[salsa::invoke(crate::callable_item_sig)] | ||
47 | fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig; | ||
48 | |||
49 | #[salsa::invoke(crate::lower::return_type_impl_traits)] | ||
50 | fn return_type_impl_traits( | ||
51 | &self, | ||
52 | def: FunctionId, | ||
53 | ) -> Option<Arc<Binders<ReturnTypeImplTraits>>>; | ||
54 | |||
55 | #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] | ||
56 | #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] | ||
57 | fn generic_predicates_for_param( | ||
58 | &self, | ||
59 | param_id: TypeParamId, | ||
60 | ) -> Arc<[Binders<GenericPredicate>]>; | ||
61 | |||
62 | #[salsa::invoke(crate::lower::generic_predicates_query)] | ||
63 | fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<GenericPredicate>]>; | ||
64 | |||
65 | #[salsa::invoke(crate::lower::generic_defaults_query)] | ||
66 | fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>; | ||
67 | |||
68 | #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] | ||
69 | fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>; | ||
70 | |||
71 | #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)] | ||
72 | fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>; | ||
73 | |||
74 | #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)] | ||
75 | fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>; | ||
76 | |||
77 | // Interned IDs for Chalk integration | ||
78 | #[salsa::interned] | ||
79 | fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId; | ||
80 | #[salsa::interned] | ||
81 | fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; | ||
82 | #[salsa::interned] | ||
83 | fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId; | ||
84 | #[salsa::interned] | ||
85 | fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> ClosureId; | ||
86 | |||
87 | #[salsa::invoke(chalk::associated_ty_data_query)] | ||
88 | fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc<chalk::AssociatedTyDatum>; | ||
89 | |||
90 | #[salsa::invoke(chalk::trait_datum_query)] | ||
91 | fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>; | ||
92 | |||
93 | #[salsa::invoke(chalk::struct_datum_query)] | ||
94 | fn struct_datum(&self, krate: CrateId, struct_id: chalk::AdtId) -> Arc<chalk::StructDatum>; | ||
95 | |||
96 | #[salsa::invoke(crate::traits::chalk::impl_datum_query)] | ||
97 | fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>; | ||
98 | |||
99 | #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)] | ||
100 | fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>; | ||
101 | |||
102 | #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] | ||
103 | fn associated_ty_value( | ||
104 | &self, | ||
105 | krate: CrateId, | ||
106 | id: chalk::AssociatedTyValueId, | ||
107 | ) -> Arc<chalk::AssociatedTyValue>; | ||
108 | |||
109 | #[salsa::invoke(crate::traits::trait_solve_query)] | ||
110 | fn trait_solve( | ||
111 | &self, | ||
112 | krate: CrateId, | ||
113 | goal: crate::Canonical<crate::InEnvironment<crate::Obligation>>, | ||
114 | ) -> Option<crate::traits::Solution>; | ||
115 | |||
116 | #[salsa::invoke(crate::traits::chalk::program_clauses_for_chalk_env_query)] | ||
117 | fn program_clauses_for_chalk_env( | ||
118 | &self, | ||
119 | krate: CrateId, | ||
120 | env: chalk_ir::Environment<chalk::Interner>, | ||
121 | ) -> chalk_ir::ProgramClauses<chalk::Interner>; | ||
122 | } | ||
123 | |||
124 | fn infer_wait(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { | ||
125 | let _p = profile::span("infer:wait").detail(|| match def { | ||
126 | DefWithBodyId::FunctionId(it) => db.function_data(it).name.to_string(), | ||
127 | DefWithBodyId::StaticId(it) => { | ||
128 | db.static_data(it).name.clone().unwrap_or_else(Name::missing).to_string() | ||
129 | } | ||
130 | DefWithBodyId::ConstId(it) => { | ||
131 | db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string() | ||
132 | } | ||
133 | }); | ||
134 | db.infer_query(def) | ||
135 | } | ||
136 | |||
137 | #[test] | ||
138 | fn hir_database_is_object_safe() { | ||
139 | fn _assert_object_safe(_: &dyn HirDatabase) {} | ||
140 | } | ||
141 | |||
142 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
143 | pub struct GlobalTypeParamId(salsa::InternId); | ||
144 | impl_intern_key!(GlobalTypeParamId); | ||
145 | |||
146 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
147 | pub struct InternedOpaqueTyId(salsa::InternId); | ||
148 | impl_intern_key!(InternedOpaqueTyId); | ||
149 | |||
150 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
151 | pub struct ClosureId(salsa::InternId); | ||
152 | impl_intern_key!(ClosureId); | ||
153 | |||
154 | /// This exists just for Chalk, because Chalk just has a single `FnDefId` where | ||
155 | /// we have different IDs for struct and enum variant constructors. | ||
156 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] | ||
157 | pub struct InternedCallableDefId(salsa::InternId); | ||
158 | impl_intern_key!(InternedCallableDefId); | ||
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs new file mode 100644 index 000000000..ae0cf8d09 --- /dev/null +++ b/crates/hir_ty/src/diagnostics.rs | |||
@@ -0,0 +1,444 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | mod expr; | ||
3 | mod match_check; | ||
4 | mod unsafe_check; | ||
5 | |||
6 | use std::any::Any; | ||
7 | |||
8 | use hir_def::DefWithBodyId; | ||
9 | use hir_expand::diagnostics::{Diagnostic, DiagnosticSink}; | ||
10 | use hir_expand::{name::Name, HirFileId, InFile}; | ||
11 | use stdx::format_to; | ||
12 | use syntax::{ast, AstPtr, SyntaxNodePtr}; | ||
13 | |||
14 | use crate::db::HirDatabase; | ||
15 | |||
16 | pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; | ||
17 | |||
18 | pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) { | ||
19 | let _p = profile::span("validate_body"); | ||
20 | let infer = db.infer(owner); | ||
21 | infer.add_diagnostics(db, owner, sink); | ||
22 | let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink); | ||
23 | validator.validate_body(db); | ||
24 | let mut validator = unsafe_check::UnsafeValidator::new(owner, infer, sink); | ||
25 | validator.validate_body(db); | ||
26 | } | ||
27 | |||
28 | #[derive(Debug)] | ||
29 | pub struct NoSuchField { | ||
30 | pub file: HirFileId, | ||
31 | pub field: AstPtr<ast::RecordExprField>, | ||
32 | } | ||
33 | |||
34 | impl Diagnostic for NoSuchField { | ||
35 | fn message(&self) -> String { | ||
36 | "no such field".to_string() | ||
37 | } | ||
38 | |||
39 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
40 | InFile::new(self.file, self.field.clone().into()) | ||
41 | } | ||
42 | |||
43 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
44 | self | ||
45 | } | ||
46 | } | ||
47 | |||
48 | #[derive(Debug)] | ||
49 | pub struct MissingFields { | ||
50 | pub file: HirFileId, | ||
51 | pub field_list_parent: AstPtr<ast::RecordExpr>, | ||
52 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
53 | pub missed_fields: Vec<Name>, | ||
54 | } | ||
55 | |||
56 | impl Diagnostic for MissingFields { | ||
57 | fn message(&self) -> String { | ||
58 | let mut buf = String::from("Missing structure fields:\n"); | ||
59 | for field in &self.missed_fields { | ||
60 | format_to!(buf, "- {}\n", field); | ||
61 | } | ||
62 | buf | ||
63 | } | ||
64 | |||
65 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
66 | InFile { | ||
67 | file_id: self.file, | ||
68 | value: self | ||
69 | .field_list_parent_path | ||
70 | .clone() | ||
71 | .map(SyntaxNodePtr::from) | ||
72 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
73 | } | ||
74 | } | ||
75 | |||
76 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
77 | self | ||
78 | } | ||
79 | } | ||
80 | |||
81 | #[derive(Debug)] | ||
82 | pub struct MissingPatFields { | ||
83 | pub file: HirFileId, | ||
84 | pub field_list_parent: AstPtr<ast::RecordPat>, | ||
85 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
86 | pub missed_fields: Vec<Name>, | ||
87 | } | ||
88 | |||
89 | impl Diagnostic for MissingPatFields { | ||
90 | fn message(&self) -> String { | ||
91 | let mut buf = String::from("Missing structure fields:\n"); | ||
92 | for field in &self.missed_fields { | ||
93 | format_to!(buf, "- {}\n", field); | ||
94 | } | ||
95 | buf | ||
96 | } | ||
97 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
98 | InFile { | ||
99 | file_id: self.file, | ||
100 | value: self | ||
101 | .field_list_parent_path | ||
102 | .clone() | ||
103 | .map(SyntaxNodePtr::from) | ||
104 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
105 | } | ||
106 | } | ||
107 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
108 | self | ||
109 | } | ||
110 | } | ||
111 | |||
112 | #[derive(Debug)] | ||
113 | pub struct MissingMatchArms { | ||
114 | pub file: HirFileId, | ||
115 | pub match_expr: AstPtr<ast::Expr>, | ||
116 | pub arms: AstPtr<ast::MatchArmList>, | ||
117 | } | ||
118 | |||
119 | impl Diagnostic for MissingMatchArms { | ||
120 | fn message(&self) -> String { | ||
121 | String::from("Missing match arm") | ||
122 | } | ||
123 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
124 | InFile { file_id: self.file, value: self.match_expr.clone().into() } | ||
125 | } | ||
126 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
127 | self | ||
128 | } | ||
129 | } | ||
130 | |||
131 | #[derive(Debug)] | ||
132 | pub struct MissingOkInTailExpr { | ||
133 | pub file: HirFileId, | ||
134 | pub expr: AstPtr<ast::Expr>, | ||
135 | } | ||
136 | |||
137 | impl Diagnostic for MissingOkInTailExpr { | ||
138 | fn message(&self) -> String { | ||
139 | "wrap return expression in Ok".to_string() | ||
140 | } | ||
141 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
142 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
143 | } | ||
144 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
145 | self | ||
146 | } | ||
147 | } | ||
148 | |||
149 | #[derive(Debug)] | ||
150 | pub struct BreakOutsideOfLoop { | ||
151 | pub file: HirFileId, | ||
152 | pub expr: AstPtr<ast::Expr>, | ||
153 | } | ||
154 | |||
155 | impl Diagnostic for BreakOutsideOfLoop { | ||
156 | fn message(&self) -> String { | ||
157 | "break outside of loop".to_string() | ||
158 | } | ||
159 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
160 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
161 | } | ||
162 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
163 | self | ||
164 | } | ||
165 | } | ||
166 | |||
167 | #[derive(Debug)] | ||
168 | pub struct MissingUnsafe { | ||
169 | pub file: HirFileId, | ||
170 | pub expr: AstPtr<ast::Expr>, | ||
171 | } | ||
172 | |||
173 | impl Diagnostic for MissingUnsafe { | ||
174 | fn message(&self) -> String { | ||
175 | format!("This operation is unsafe and requires an unsafe function or block") | ||
176 | } | ||
177 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
178 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
179 | } | ||
180 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
181 | self | ||
182 | } | ||
183 | } | ||
184 | |||
185 | #[derive(Debug)] | ||
186 | pub struct MismatchedArgCount { | ||
187 | pub file: HirFileId, | ||
188 | pub call_expr: AstPtr<ast::Expr>, | ||
189 | pub expected: usize, | ||
190 | pub found: usize, | ||
191 | } | ||
192 | |||
193 | impl Diagnostic for MismatchedArgCount { | ||
194 | fn message(&self) -> String { | ||
195 | let s = if self.expected == 1 { "" } else { "s" }; | ||
196 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) | ||
197 | } | ||
198 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
199 | InFile { file_id: self.file, value: self.call_expr.clone().into() } | ||
200 | } | ||
201 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
202 | self | ||
203 | } | ||
204 | fn is_experimental(&self) -> bool { | ||
205 | true | ||
206 | } | ||
207 | } | ||
208 | |||
209 | #[cfg(test)] | ||
210 | mod tests { | ||
211 | use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; | ||
212 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; | ||
213 | use hir_expand::{ | ||
214 | db::AstDatabase, | ||
215 | diagnostics::{Diagnostic, DiagnosticSinkBuilder}, | ||
216 | }; | ||
217 | use rustc_hash::FxHashMap; | ||
218 | use syntax::{TextRange, TextSize}; | ||
219 | |||
220 | use crate::{diagnostics::validate_body, test_db::TestDB}; | ||
221 | |||
222 | impl TestDB { | ||
223 | fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) { | ||
224 | let crate_graph = self.crate_graph(); | ||
225 | for krate in crate_graph.iter() { | ||
226 | let crate_def_map = self.crate_def_map(krate); | ||
227 | |||
228 | let mut fns = Vec::new(); | ||
229 | for (module_id, _) in crate_def_map.modules.iter() { | ||
230 | for decl in crate_def_map[module_id].scope.declarations() { | ||
231 | if let ModuleDefId::FunctionId(f) = decl { | ||
232 | fns.push(f) | ||
233 | } | ||
234 | } | ||
235 | |||
236 | for impl_id in crate_def_map[module_id].scope.impls() { | ||
237 | let impl_data = self.impl_data(impl_id); | ||
238 | for item in impl_data.items.iter() { | ||
239 | if let AssocItemId::FunctionId(f) = item { | ||
240 | fns.push(*f) | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | for f in fns { | ||
247 | let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); | ||
248 | validate_body(self, f.into(), &mut sink); | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | |||
254 | pub(crate) fn check_diagnostics(ra_fixture: &str) { | ||
255 | let db = TestDB::with_files(ra_fixture); | ||
256 | let annotations = db.extract_annotations(); | ||
257 | |||
258 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); | ||
259 | db.diagnostics(|d| { | ||
260 | let src = d.display_source(); | ||
261 | let root = db.parse_or_expand(src.file_id).unwrap(); | ||
262 | // FIXME: macros... | ||
263 | let file_id = src.file_id.original_file(&db); | ||
264 | let range = src.value.to_node(&root).text_range(); | ||
265 | let message = d.message().to_owned(); | ||
266 | actual.entry(file_id).or_default().push((range, message)); | ||
267 | }); | ||
268 | |||
269 | for (file_id, diags) in actual.iter_mut() { | ||
270 | diags.sort_by_key(|it| it.0.start()); | ||
271 | let text = db.file_text(*file_id); | ||
272 | // For multiline spans, place them on line start | ||
273 | for (range, content) in diags { | ||
274 | if text[*range].contains('\n') { | ||
275 | *range = TextRange::new(range.start(), range.start() + TextSize::from(1)); | ||
276 | *content = format!("... {}", content); | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | assert_eq!(annotations, actual); | ||
282 | } | ||
283 | |||
284 | #[test] | ||
285 | fn no_such_field_diagnostics() { | ||
286 | check_diagnostics( | ||
287 | r#" | ||
288 | struct S { foo: i32, bar: () } | ||
289 | impl S { | ||
290 | fn new() -> S { | ||
291 | S { | ||
292 | //^ Missing structure fields: | ||
293 | //| - bar | ||
294 | foo: 92, | ||
295 | baz: 62, | ||
296 | //^^^^^^^ no such field | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | "#, | ||
301 | ); | ||
302 | } | ||
303 | #[test] | ||
304 | fn no_such_field_with_feature_flag_diagnostics() { | ||
305 | check_diagnostics( | ||
306 | r#" | ||
307 | //- /lib.rs crate:foo cfg:feature=foo | ||
308 | struct MyStruct { | ||
309 | my_val: usize, | ||
310 | #[cfg(feature = "foo")] | ||
311 | bar: bool, | ||
312 | } | ||
313 | |||
314 | impl MyStruct { | ||
315 | #[cfg(feature = "foo")] | ||
316 | pub(crate) fn new(my_val: usize, bar: bool) -> Self { | ||
317 | Self { my_val, bar } | ||
318 | } | ||
319 | #[cfg(not(feature = "foo"))] | ||
320 | pub(crate) fn new(my_val: usize, _bar: bool) -> Self { | ||
321 | Self { my_val } | ||
322 | } | ||
323 | } | ||
324 | "#, | ||
325 | ); | ||
326 | } | ||
327 | |||
328 | #[test] | ||
329 | fn no_such_field_enum_with_feature_flag_diagnostics() { | ||
330 | check_diagnostics( | ||
331 | r#" | ||
332 | //- /lib.rs crate:foo cfg:feature=foo | ||
333 | enum Foo { | ||
334 | #[cfg(not(feature = "foo"))] | ||
335 | Buz, | ||
336 | #[cfg(feature = "foo")] | ||
337 | Bar, | ||
338 | Baz | ||
339 | } | ||
340 | |||
341 | fn test_fn(f: Foo) { | ||
342 | match f { | ||
343 | Foo::Bar => {}, | ||
344 | Foo::Baz => {}, | ||
345 | } | ||
346 | } | ||
347 | "#, | ||
348 | ); | ||
349 | } | ||
350 | |||
351 | #[test] | ||
352 | fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { | ||
353 | check_diagnostics( | ||
354 | r#" | ||
355 | //- /lib.rs crate:foo cfg:feature=foo | ||
356 | struct S { | ||
357 | #[cfg(feature = "foo")] | ||
358 | foo: u32, | ||
359 | #[cfg(not(feature = "foo"))] | ||
360 | bar: u32, | ||
361 | } | ||
362 | |||
363 | impl S { | ||
364 | #[cfg(feature = "foo")] | ||
365 | fn new(foo: u32) -> Self { | ||
366 | Self { foo } | ||
367 | } | ||
368 | #[cfg(not(feature = "foo"))] | ||
369 | fn new(bar: u32) -> Self { | ||
370 | Self { bar } | ||
371 | } | ||
372 | fn new2(bar: u32) -> Self { | ||
373 | #[cfg(feature = "foo")] | ||
374 | { Self { foo: bar } } | ||
375 | #[cfg(not(feature = "foo"))] | ||
376 | { Self { bar } } | ||
377 | } | ||
378 | fn new2(val: u32) -> Self { | ||
379 | Self { | ||
380 | #[cfg(feature = "foo")] | ||
381 | foo: val, | ||
382 | #[cfg(not(feature = "foo"))] | ||
383 | bar: val, | ||
384 | } | ||
385 | } | ||
386 | } | ||
387 | "#, | ||
388 | ); | ||
389 | } | ||
390 | |||
391 | #[test] | ||
392 | fn no_such_field_with_type_macro() { | ||
393 | check_diagnostics( | ||
394 | r#" | ||
395 | macro_rules! Type { () => { u32 }; } | ||
396 | struct Foo { bar: Type![] } | ||
397 | |||
398 | impl Foo { | ||
399 | fn new() -> Self { | ||
400 | Foo { bar: 0 } | ||
401 | } | ||
402 | } | ||
403 | "#, | ||
404 | ); | ||
405 | } | ||
406 | |||
407 | #[test] | ||
408 | fn missing_record_pat_field_diagnostic() { | ||
409 | check_diagnostics( | ||
410 | r#" | ||
411 | struct S { foo: i32, bar: () } | ||
412 | fn baz(s: S) { | ||
413 | let S { foo: _ } = s; | ||
414 | //^ Missing structure fields: | ||
415 | //| - bar | ||
416 | } | ||
417 | "#, | ||
418 | ); | ||
419 | } | ||
420 | |||
421 | #[test] | ||
422 | fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() { | ||
423 | check_diagnostics( | ||
424 | r" | ||
425 | struct S { foo: i32, bar: () } | ||
426 | fn baz(s: S) -> i32 { | ||
427 | match s { | ||
428 | S { foo, .. } => foo, | ||
429 | } | ||
430 | } | ||
431 | ", | ||
432 | ) | ||
433 | } | ||
434 | |||
435 | #[test] | ||
436 | fn break_outside_of_loop() { | ||
437 | check_diagnostics( | ||
438 | r#" | ||
439 | fn foo() { break; } | ||
440 | //^^^^^ break outside of loop | ||
441 | "#, | ||
442 | ); | ||
443 | } | ||
444 | } | ||
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs new file mode 100644 index 000000000..278a4b947 --- /dev/null +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -0,0 +1,569 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use hir_def::{path::path, resolver::HasResolver, AdtId, DefWithBodyId}; | ||
6 | use hir_expand::diagnostics::DiagnosticSink; | ||
7 | use rustc_hash::FxHashSet; | ||
8 | use syntax::{ast, AstPtr}; | ||
9 | |||
10 | use crate::{ | ||
11 | db::HirDatabase, | ||
12 | diagnostics::{ | ||
13 | match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, | ||
14 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields, | ||
15 | }, | ||
16 | utils::variant_data, | ||
17 | ApplicationTy, InferenceResult, Ty, TypeCtor, | ||
18 | }; | ||
19 | |||
20 | pub use hir_def::{ | ||
21 | body::{ | ||
22 | scope::{ExprScopes, ScopeEntry, ScopeId}, | ||
23 | Body, BodySourceMap, ExprPtr, ExprSource, PatPtr, PatSource, | ||
24 | }, | ||
25 | expr::{ | ||
26 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, | ||
27 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, | ||
28 | }, | ||
29 | src::HasSource, | ||
30 | LocalFieldId, Lookup, VariantId, | ||
31 | }; | ||
32 | |||
33 | pub(super) struct ExprValidator<'a, 'b: 'a> { | ||
34 | owner: DefWithBodyId, | ||
35 | infer: Arc<InferenceResult>, | ||
36 | sink: &'a mut DiagnosticSink<'b>, | ||
37 | } | ||
38 | |||
39 | impl<'a, 'b> ExprValidator<'a, 'b> { | ||
40 | pub(super) fn new( | ||
41 | owner: DefWithBodyId, | ||
42 | infer: Arc<InferenceResult>, | ||
43 | sink: &'a mut DiagnosticSink<'b>, | ||
44 | ) -> ExprValidator<'a, 'b> { | ||
45 | ExprValidator { owner, infer, sink } | ||
46 | } | ||
47 | |||
48 | pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { | ||
49 | let body = db.body(self.owner.into()); | ||
50 | |||
51 | for (id, expr) in body.exprs.iter() { | ||
52 | if let Some((variant_def, missed_fields, true)) = | ||
53 | record_literal_missing_fields(db, &self.infer, id, expr) | ||
54 | { | ||
55 | self.create_record_literal_missing_fields_diagnostic( | ||
56 | id, | ||
57 | db, | ||
58 | variant_def, | ||
59 | missed_fields, | ||
60 | ); | ||
61 | } | ||
62 | |||
63 | match expr { | ||
64 | Expr::Match { expr, arms } => { | ||
65 | self.validate_match(id, *expr, arms, db, self.infer.clone()); | ||
66 | } | ||
67 | Expr::Call { .. } | Expr::MethodCall { .. } => { | ||
68 | self.validate_call(db, id, expr); | ||
69 | } | ||
70 | _ => {} | ||
71 | } | ||
72 | } | ||
73 | for (id, pat) in body.pats.iter() { | ||
74 | if let Some((variant_def, missed_fields, true)) = | ||
75 | record_pattern_missing_fields(db, &self.infer, id, pat) | ||
76 | { | ||
77 | self.create_record_pattern_missing_fields_diagnostic( | ||
78 | id, | ||
79 | db, | ||
80 | variant_def, | ||
81 | missed_fields, | ||
82 | ); | ||
83 | } | ||
84 | } | ||
85 | let body_expr = &body[body.body_expr]; | ||
86 | if let Expr::Block { tail: Some(t), .. } = body_expr { | ||
87 | self.validate_results_in_tail_expr(body.body_expr, *t, db); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | fn create_record_literal_missing_fields_diagnostic( | ||
92 | &mut self, | ||
93 | id: ExprId, | ||
94 | db: &dyn HirDatabase, | ||
95 | variant_def: VariantId, | ||
96 | missed_fields: Vec<LocalFieldId>, | ||
97 | ) { | ||
98 | // XXX: only look at source_map if we do have missing fields | ||
99 | let (_, source_map) = db.body_with_source_map(self.owner.into()); | ||
100 | |||
101 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | ||
102 | let root = source_ptr.file_syntax(db.upcast()); | ||
103 | if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) { | ||
104 | if let Some(_) = record_expr.record_expr_field_list() { | ||
105 | let variant_data = variant_data(db.upcast(), variant_def); | ||
106 | let missed_fields = missed_fields | ||
107 | .into_iter() | ||
108 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
109 | .collect(); | ||
110 | self.sink.push(MissingFields { | ||
111 | file: source_ptr.file_id, | ||
112 | field_list_parent: AstPtr::new(&record_expr), | ||
113 | field_list_parent_path: record_expr.path().map(|path| AstPtr::new(&path)), | ||
114 | missed_fields, | ||
115 | }) | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | |||
121 | fn create_record_pattern_missing_fields_diagnostic( | ||
122 | &mut self, | ||
123 | id: PatId, | ||
124 | db: &dyn HirDatabase, | ||
125 | variant_def: VariantId, | ||
126 | missed_fields: Vec<LocalFieldId>, | ||
127 | ) { | ||
128 | // XXX: only look at source_map if we do have missing fields | ||
129 | let (_, source_map) = db.body_with_source_map(self.owner.into()); | ||
130 | |||
131 | if let Ok(source_ptr) = source_map.pat_syntax(id) { | ||
132 | if let Some(expr) = source_ptr.value.as_ref().left() { | ||
133 | let root = source_ptr.file_syntax(db.upcast()); | ||
134 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | ||
135 | if let Some(_) = record_pat.record_pat_field_list() { | ||
136 | let variant_data = variant_data(db.upcast(), variant_def); | ||
137 | let missed_fields = missed_fields | ||
138 | .into_iter() | ||
139 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
140 | .collect(); | ||
141 | self.sink.push(MissingPatFields { | ||
142 | file: source_ptr.file_id, | ||
143 | field_list_parent: AstPtr::new(&record_pat), | ||
144 | field_list_parent_path: record_pat | ||
145 | .path() | ||
146 | .map(|path| AstPtr::new(&path)), | ||
147 | missed_fields, | ||
148 | }) | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr) -> Option<()> { | ||
156 | // Check that the number of arguments matches the number of parameters. | ||
157 | |||
158 | // FIXME: Due to shortcomings in the current type system implementation, only emit this | ||
159 | // diagnostic if there are no type mismatches in the containing function. | ||
160 | if self.infer.type_mismatches.iter().next().is_some() { | ||
161 | return Some(()); | ||
162 | } | ||
163 | |||
164 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); | ||
165 | let (sig, args) = match expr { | ||
166 | Expr::Call { callee, args } => { | ||
167 | let callee = &self.infer.type_of_expr[*callee]; | ||
168 | let sig = callee.callable_sig(db)?; | ||
169 | (sig, args.clone()) | ||
170 | } | ||
171 | Expr::MethodCall { receiver, args, .. } => { | ||
172 | let mut args = args.clone(); | ||
173 | args.insert(0, *receiver); | ||
174 | |||
175 | // FIXME: note that we erase information about substs here. This | ||
176 | // is not right, but, luckily, doesn't matter as we care only | ||
177 | // about the number of params | ||
178 | let callee = self.infer.method_resolution(call_id)?; | ||
179 | let sig = db.callable_item_signature(callee.into()).value; | ||
180 | |||
181 | (sig, args) | ||
182 | } | ||
183 | _ => return None, | ||
184 | }; | ||
185 | |||
186 | if sig.is_varargs { | ||
187 | return None; | ||
188 | } | ||
189 | |||
190 | let params = sig.params(); | ||
191 | |||
192 | let mut param_count = params.len(); | ||
193 | let mut arg_count = args.len(); | ||
194 | |||
195 | if arg_count != param_count { | ||
196 | let (_, source_map) = db.body_with_source_map(self.owner.into()); | ||
197 | if let Ok(source_ptr) = source_map.expr_syntax(call_id) { | ||
198 | if is_method_call { | ||
199 | param_count -= 1; | ||
200 | arg_count -= 1; | ||
201 | } | ||
202 | self.sink.push(MismatchedArgCount { | ||
203 | file: source_ptr.file_id, | ||
204 | call_expr: source_ptr.value, | ||
205 | expected: param_count, | ||
206 | found: arg_count, | ||
207 | }); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | None | ||
212 | } | ||
213 | |||
214 | fn validate_match( | ||
215 | &mut self, | ||
216 | id: ExprId, | ||
217 | match_expr: ExprId, | ||
218 | arms: &[MatchArm], | ||
219 | db: &dyn HirDatabase, | ||
220 | infer: Arc<InferenceResult>, | ||
221 | ) { | ||
222 | let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) = | ||
223 | db.body_with_source_map(self.owner.into()); | ||
224 | |||
225 | let match_expr_ty = match infer.type_of_expr.get(match_expr) { | ||
226 | // If we can't resolve the type of the match expression | ||
227 | // we cannot perform exhaustiveness checks. | ||
228 | None | Some(Ty::Unknown) => return, | ||
229 | Some(ty) => ty, | ||
230 | }; | ||
231 | |||
232 | let cx = MatchCheckCtx { match_expr, body, infer: infer.clone(), db }; | ||
233 | let pats = arms.iter().map(|arm| arm.pat); | ||
234 | |||
235 | let mut seen = Matrix::empty(); | ||
236 | for pat in pats { | ||
237 | if let Some(pat_ty) = infer.type_of_pat.get(pat) { | ||
238 | // We only include patterns whose type matches the type | ||
239 | // of the match expression. If we had a InvalidMatchArmPattern | ||
240 | // diagnostic or similar we could raise that in an else | ||
241 | // block here. | ||
242 | // | ||
243 | // When comparing the types, we also have to consider that rustc | ||
244 | // will automatically de-reference the match expression type if | ||
245 | // necessary. | ||
246 | // | ||
247 | // FIXME we should use the type checker for this. | ||
248 | if pat_ty == match_expr_ty | ||
249 | || match_expr_ty | ||
250 | .as_reference() | ||
251 | .map(|(match_expr_ty, _)| match_expr_ty == pat_ty) | ||
252 | .unwrap_or(false) | ||
253 | { | ||
254 | // If we had a NotUsefulMatchArm diagnostic, we could | ||
255 | // check the usefulness of each pattern as we added it | ||
256 | // to the matrix here. | ||
257 | let v = PatStack::from_pattern(pat); | ||
258 | seen.push(&cx, v); | ||
259 | continue; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | // If we can't resolve the type of a pattern, or the pattern type doesn't | ||
264 | // fit the match expression, we skip this diagnostic. Skipping the entire | ||
265 | // diagnostic rather than just not including this match arm is preferred | ||
266 | // to avoid the chance of false positives. | ||
267 | return; | ||
268 | } | ||
269 | |||
270 | match is_useful(&cx, &seen, &PatStack::from_wild()) { | ||
271 | Ok(Usefulness::Useful) => (), | ||
272 | // if a wildcard pattern is not useful, then all patterns are covered | ||
273 | Ok(Usefulness::NotUseful) => return, | ||
274 | // this path is for unimplemented checks, so we err on the side of not | ||
275 | // reporting any errors | ||
276 | _ => return, | ||
277 | } | ||
278 | |||
279 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | ||
280 | let root = source_ptr.file_syntax(db.upcast()); | ||
281 | if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) { | ||
282 | if let (Some(match_expr), Some(arms)) = | ||
283 | (match_expr.expr(), match_expr.match_arm_list()) | ||
284 | { | ||
285 | self.sink.push(MissingMatchArms { | ||
286 | file: source_ptr.file_id, | ||
287 | match_expr: AstPtr::new(&match_expr), | ||
288 | arms: AstPtr::new(&arms), | ||
289 | }) | ||
290 | } | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | |||
295 | fn validate_results_in_tail_expr(&mut self, body_id: ExprId, id: ExprId, db: &dyn HirDatabase) { | ||
296 | // the mismatch will be on the whole block currently | ||
297 | let mismatch = match self.infer.type_mismatch_for_expr(body_id) { | ||
298 | Some(m) => m, | ||
299 | None => return, | ||
300 | }; | ||
301 | |||
302 | let core_result_path = path![core::result::Result]; | ||
303 | |||
304 | let resolver = self.owner.resolver(db.upcast()); | ||
305 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { | ||
306 | Some(it) => it, | ||
307 | _ => return, | ||
308 | }; | ||
309 | |||
310 | let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); | ||
311 | let params = match &mismatch.expected { | ||
312 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => { | ||
313 | parameters | ||
314 | } | ||
315 | _ => return, | ||
316 | }; | ||
317 | |||
318 | if params.len() == 2 && params[0] == mismatch.actual { | ||
319 | let (_, source_map) = db.body_with_source_map(self.owner.into()); | ||
320 | |||
321 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | ||
322 | self.sink | ||
323 | .push(MissingOkInTailExpr { file: source_ptr.file_id, expr: source_ptr.value }); | ||
324 | } | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | pub fn record_literal_missing_fields( | ||
330 | db: &dyn HirDatabase, | ||
331 | infer: &InferenceResult, | ||
332 | id: ExprId, | ||
333 | expr: &Expr, | ||
334 | ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> { | ||
335 | let (fields, exhausitve) = match expr { | ||
336 | Expr::RecordLit { path: _, fields, spread } => (fields, spread.is_none()), | ||
337 | _ => return None, | ||
338 | }; | ||
339 | |||
340 | let variant_def = infer.variant_resolution_for_expr(id)?; | ||
341 | if let VariantId::UnionId(_) = variant_def { | ||
342 | return None; | ||
343 | } | ||
344 | |||
345 | let variant_data = variant_data(db.upcast(), variant_def); | ||
346 | |||
347 | let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); | ||
348 | let missed_fields: Vec<LocalFieldId> = variant_data | ||
349 | .fields() | ||
350 | .iter() | ||
351 | .filter_map(|(f, d)| if specified_fields.contains(&d.name) { None } else { Some(f) }) | ||
352 | .collect(); | ||
353 | if missed_fields.is_empty() { | ||
354 | return None; | ||
355 | } | ||
356 | Some((variant_def, missed_fields, exhausitve)) | ||
357 | } | ||
358 | |||
359 | pub fn record_pattern_missing_fields( | ||
360 | db: &dyn HirDatabase, | ||
361 | infer: &InferenceResult, | ||
362 | id: PatId, | ||
363 | pat: &Pat, | ||
364 | ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> { | ||
365 | let (fields, exhaustive) = match pat { | ||
366 | Pat::Record { path: _, args, ellipsis } => (args, !ellipsis), | ||
367 | _ => return None, | ||
368 | }; | ||
369 | |||
370 | let variant_def = infer.variant_resolution_for_pat(id)?; | ||
371 | if let VariantId::UnionId(_) = variant_def { | ||
372 | return None; | ||
373 | } | ||
374 | |||
375 | let variant_data = variant_data(db.upcast(), variant_def); | ||
376 | |||
377 | let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); | ||
378 | let missed_fields: Vec<LocalFieldId> = variant_data | ||
379 | .fields() | ||
380 | .iter() | ||
381 | .filter_map(|(f, d)| if specified_fields.contains(&d.name) { None } else { Some(f) }) | ||
382 | .collect(); | ||
383 | if missed_fields.is_empty() { | ||
384 | return None; | ||
385 | } | ||
386 | Some((variant_def, missed_fields, exhaustive)) | ||
387 | } | ||
388 | |||
389 | #[cfg(test)] | ||
390 | mod tests { | ||
391 | use crate::diagnostics::tests::check_diagnostics; | ||
392 | |||
393 | #[test] | ||
394 | fn simple_free_fn_zero() { | ||
395 | check_diagnostics( | ||
396 | r#" | ||
397 | fn zero() {} | ||
398 | fn f() { zero(1); } | ||
399 | //^^^^^^^ Expected 0 arguments, found 1 | ||
400 | "#, | ||
401 | ); | ||
402 | |||
403 | check_diagnostics( | ||
404 | r#" | ||
405 | fn zero() {} | ||
406 | fn f() { zero(); } | ||
407 | "#, | ||
408 | ); | ||
409 | } | ||
410 | |||
411 | #[test] | ||
412 | fn simple_free_fn_one() { | ||
413 | check_diagnostics( | ||
414 | r#" | ||
415 | fn one(arg: u8) {} | ||
416 | fn f() { one(); } | ||
417 | //^^^^^ Expected 1 argument, found 0 | ||
418 | "#, | ||
419 | ); | ||
420 | |||
421 | check_diagnostics( | ||
422 | r#" | ||
423 | fn one(arg: u8) {} | ||
424 | fn f() { one(1); } | ||
425 | "#, | ||
426 | ); | ||
427 | } | ||
428 | |||
429 | #[test] | ||
430 | fn method_as_fn() { | ||
431 | check_diagnostics( | ||
432 | r#" | ||
433 | struct S; | ||
434 | impl S { fn method(&self) {} } | ||
435 | |||
436 | fn f() { | ||
437 | S::method(); | ||
438 | } //^^^^^^^^^^^ Expected 1 argument, found 0 | ||
439 | "#, | ||
440 | ); | ||
441 | |||
442 | check_diagnostics( | ||
443 | r#" | ||
444 | struct S; | ||
445 | impl S { fn method(&self) {} } | ||
446 | |||
447 | fn f() { | ||
448 | S::method(&S); | ||
449 | S.method(); | ||
450 | } | ||
451 | "#, | ||
452 | ); | ||
453 | } | ||
454 | |||
455 | #[test] | ||
456 | fn method_with_arg() { | ||
457 | check_diagnostics( | ||
458 | r#" | ||
459 | struct S; | ||
460 | impl S { fn method(&self, arg: u8) {} } | ||
461 | |||
462 | fn f() { | ||
463 | S.method(); | ||
464 | } //^^^^^^^^^^ Expected 1 argument, found 0 | ||
465 | "#, | ||
466 | ); | ||
467 | |||
468 | check_diagnostics( | ||
469 | r#" | ||
470 | struct S; | ||
471 | impl S { fn method(&self, arg: u8) {} } | ||
472 | |||
473 | fn f() { | ||
474 | S::method(&S, 0); | ||
475 | S.method(1); | ||
476 | } | ||
477 | "#, | ||
478 | ); | ||
479 | } | ||
480 | |||
481 | #[test] | ||
482 | fn tuple_struct() { | ||
483 | check_diagnostics( | ||
484 | r#" | ||
485 | struct Tup(u8, u16); | ||
486 | fn f() { | ||
487 | Tup(0); | ||
488 | } //^^^^^^ Expected 2 arguments, found 1 | ||
489 | "#, | ||
490 | ) | ||
491 | } | ||
492 | |||
493 | #[test] | ||
494 | fn enum_variant() { | ||
495 | check_diagnostics( | ||
496 | r#" | ||
497 | enum En { Variant(u8, u16), } | ||
498 | fn f() { | ||
499 | En::Variant(0); | ||
500 | } //^^^^^^^^^^^^^^ Expected 2 arguments, found 1 | ||
501 | "#, | ||
502 | ) | ||
503 | } | ||
504 | |||
505 | #[test] | ||
506 | fn enum_variant_type_macro() { | ||
507 | check_diagnostics( | ||
508 | r#" | ||
509 | macro_rules! Type { | ||
510 | () => { u32 }; | ||
511 | } | ||
512 | enum Foo { | ||
513 | Bar(Type![]) | ||
514 | } | ||
515 | impl Foo { | ||
516 | fn new() { | ||
517 | Foo::Bar(0); | ||
518 | Foo::Bar(0, 1); | ||
519 | //^^^^^^^^^^^^^^ Expected 1 argument, found 2 | ||
520 | Foo::Bar(); | ||
521 | //^^^^^^^^^^ Expected 1 argument, found 0 | ||
522 | } | ||
523 | } | ||
524 | "#, | ||
525 | ); | ||
526 | } | ||
527 | |||
528 | #[test] | ||
529 | fn varargs() { | ||
530 | check_diagnostics( | ||
531 | r#" | ||
532 | extern "C" { | ||
533 | fn fixed(fixed: u8); | ||
534 | fn varargs(fixed: u8, ...); | ||
535 | fn varargs2(...); | ||
536 | } | ||
537 | |||
538 | fn f() { | ||
539 | unsafe { | ||
540 | fixed(0); | ||
541 | fixed(0, 1); | ||
542 | //^^^^^^^^^^^ Expected 1 argument, found 2 | ||
543 | varargs(0); | ||
544 | varargs(0, 1); | ||
545 | varargs2(); | ||
546 | varargs2(0); | ||
547 | varargs2(0, 1); | ||
548 | } | ||
549 | } | ||
550 | "#, | ||
551 | ) | ||
552 | } | ||
553 | |||
554 | #[test] | ||
555 | fn arg_count_lambda() { | ||
556 | check_diagnostics( | ||
557 | r#" | ||
558 | fn main() { | ||
559 | let f = |()| (); | ||
560 | f(); | ||
561 | //^^^ Expected 1 argument, found 0 | ||
562 | f(()); | ||
563 | f((), ()); | ||
564 | //^^^^^^^^^ Expected 1 argument, found 2 | ||
565 | } | ||
566 | "#, | ||
567 | ) | ||
568 | } | ||
569 | } | ||
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs new file mode 100644 index 000000000..5bd03f2ac --- /dev/null +++ b/crates/hir_ty/src/diagnostics/match_check.rs | |||
@@ -0,0 +1,1438 @@ | |||
1 | //! This module implements match statement exhaustiveness checking and usefulness checking | ||
2 | //! for match arms. | ||
3 | //! | ||
4 | //! It is modeled on the rustc module `librustc_mir_build::hair::pattern::_match`, which | ||
5 | //! contains very detailed documentation about the algorithms used here. I've duplicated | ||
6 | //! most of that documentation below. | ||
7 | //! | ||
8 | //! This file includes the logic for exhaustiveness and usefulness checking for | ||
9 | //! pattern-matching. Specifically, given a list of patterns for a type, we can | ||
10 | //! tell whether: | ||
11 | //! - (a) the patterns cover every possible constructor for the type (exhaustiveness). | ||
12 | //! - (b) each pattern is necessary (usefulness). | ||
13 | //! | ||
14 | //! The algorithm implemented here is a modified version of the one described in | ||
15 | //! <http://moscova.inria.fr/~maranget/papers/warn/index.html>. | ||
16 | //! However, to save future implementors from reading the original paper, we | ||
17 | //! summarise the algorithm here to hopefully save time and be a little clearer | ||
18 | //! (without being so rigorous). | ||
19 | //! | ||
20 | //! The core of the algorithm revolves about a "usefulness" check. In particular, we | ||
21 | //! are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as | ||
22 | //! a matrix). `U(P, p)` represents whether, given an existing list of patterns | ||
23 | //! `P_1 ..= P_m`, adding a new pattern `p` will be "useful" (that is, cover previously- | ||
24 | //! uncovered values of the type). | ||
25 | //! | ||
26 | //! If we have this predicate, then we can easily compute both exhaustiveness of an | ||
27 | //! entire set of patterns and the individual usefulness of each one. | ||
28 | //! (a) the set of patterns is exhaustive iff `U(P, _)` is false (i.e., adding a wildcard | ||
29 | //! match doesn't increase the number of values we're matching) | ||
30 | //! (b) a pattern `P_i` is not useful if `U(P[0..=(i-1), P_i)` is false (i.e., adding a | ||
31 | //! pattern to those that have come before it doesn't increase the number of values | ||
32 | //! we're matching). | ||
33 | //! | ||
34 | //! During the course of the algorithm, the rows of the matrix won't just be individual patterns, | ||
35 | //! but rather partially-deconstructed patterns in the form of a list of patterns. The paper | ||
36 | //! calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the | ||
37 | //! new pattern `p`. | ||
38 | //! | ||
39 | //! For example, say we have the following: | ||
40 | //! | ||
41 | //! ```ignore | ||
42 | //! // x: (Option<bool>, Result<()>) | ||
43 | //! match x { | ||
44 | //! (Some(true), _) => (), | ||
45 | //! (None, Err(())) => (), | ||
46 | //! (None, Err(_)) => (), | ||
47 | //! } | ||
48 | //! ``` | ||
49 | //! | ||
50 | //! Here, the matrix `P` starts as: | ||
51 | //! | ||
52 | //! ```text | ||
53 | //! [ | ||
54 | //! [(Some(true), _)], | ||
55 | //! [(None, Err(()))], | ||
56 | //! [(None, Err(_))], | ||
57 | //! ] | ||
58 | //! ``` | ||
59 | //! | ||
60 | //! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering | ||
61 | //! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because | ||
62 | //! all the values it covers are already covered by row 2. | ||
63 | //! | ||
64 | //! A list of patterns can be thought of as a stack, because we are mainly interested in the top of | ||
65 | //! the stack at any given point, and we can pop or apply constructors to get new pattern-stacks. | ||
66 | //! To match the paper, the top of the stack is at the beginning / on the left. | ||
67 | //! | ||
68 | //! There are two important operations on pattern-stacks necessary to understand the algorithm: | ||
69 | //! | ||
70 | //! 1. We can pop a given constructor off the top of a stack. This operation is called | ||
71 | //! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or | ||
72 | //! `None`) and `p` a pattern-stack. | ||
73 | //! If the pattern on top of the stack can cover `c`, this removes the constructor and | ||
74 | //! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns. | ||
75 | //! Otherwise the pattern-stack is discarded. | ||
76 | //! This essentially filters those pattern-stacks whose top covers the constructor `c` and | ||
77 | //! discards the others. | ||
78 | //! | ||
79 | //! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we | ||
80 | //! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the | ||
81 | //! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get | ||
82 | //! nothing back. | ||
83 | //! | ||
84 | //! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` | ||
85 | //! on top of the stack, and we have four cases: | ||
86 | //! | ||
87 | //! * 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We push onto | ||
88 | //! the stack the arguments of this constructor, and return the result: | ||
89 | //! | ||
90 | //! r_1, .., r_a, p_2, .., p_n | ||
91 | //! | ||
92 | //! * 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠c'`. We discard the current stack and return | ||
93 | //! nothing. | ||
94 | //! * 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has | ||
95 | //! arguments (its arity), and return the resulting stack: | ||
96 | //! | ||
97 | //! _, .., _, p_2, .., p_n | ||
98 | //! | ||
99 | //! * 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting stack: | ||
100 | //! | ||
101 | //! S(c, (r_1, p_2, .., p_n)) | ||
102 | //! S(c, (r_2, p_2, .., p_n)) | ||
103 | //! | ||
104 | //! 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is | ||
105 | //! a pattern-stack. | ||
106 | //! This is used when we know there are missing constructor cases, but there might be | ||
107 | //! existing wildcard patterns, so to check the usefulness of the matrix, we have to check | ||
108 | //! all its *other* components. | ||
109 | //! | ||
110 | //! It is computed as follows. We look at the pattern `p_1` on top of the stack, | ||
111 | //! and we have three cases: | ||
112 | //! * 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. | ||
113 | //! * 1.2. `p_1 = _`. We return the rest of the stack: | ||
114 | //! | ||
115 | //! p_2, .., p_n | ||
116 | //! | ||
117 | //! * 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting stack: | ||
118 | //! | ||
119 | //! D((r_1, p_2, .., p_n)) | ||
120 | //! D((r_2, p_2, .., p_n)) | ||
121 | //! | ||
122 | //! Note that the OR-patterns are not always used directly in Rust, but are used to derive the | ||
123 | //! exhaustive integer matching rules, so they're written here for posterity. | ||
124 | //! | ||
125 | //! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by | ||
126 | //! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with | ||
127 | //! the given constructor, and popping a wildcard keeps those rows that start with a wildcard. | ||
128 | //! | ||
129 | //! | ||
130 | //! The algorithm for computing `U` | ||
131 | //! ------------------------------- | ||
132 | //! The algorithm is inductive (on the number of columns: i.e., components of tuple patterns). | ||
133 | //! That means we're going to check the components from left-to-right, so the algorithm | ||
134 | //! operates principally on the first component of the matrix and new pattern-stack `p`. | ||
135 | //! This algorithm is realised in the `is_useful` function. | ||
136 | //! | ||
137 | //! Base case (`n = 0`, i.e., an empty tuple pattern): | ||
138 | //! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), then | ||
139 | //! `U(P, p)` is false. | ||
140 | //! - Otherwise, `P` must be empty, so `U(P, p)` is true. | ||
141 | //! | ||
142 | //! Inductive step (`n > 0`, i.e., whether there's at least one column [which may then be expanded | ||
143 | //! into further columns later]). We're going to match on the top of the new pattern-stack, `p_1`: | ||
144 | //! | ||
145 | //! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern. | ||
146 | //! Then, the usefulness of `p_1` can be reduced to whether it is useful when | ||
147 | //! we ignore all the patterns in the first column of `P` that involve other constructors. | ||
148 | //! This is where `S(c, P)` comes in: | ||
149 | //! | ||
150 | //! ```text | ||
151 | //! U(P, p) := U(S(c, P), S(c, p)) | ||
152 | //! ``` | ||
153 | //! | ||
154 | //! This special case is handled in `is_useful_specialized`. | ||
155 | //! | ||
156 | //! For example, if `P` is: | ||
157 | //! | ||
158 | //! ```text | ||
159 | //! [ | ||
160 | //! [Some(true), _], | ||
161 | //! [None, 0], | ||
162 | //! ] | ||
163 | //! ``` | ||
164 | //! | ||
165 | //! and `p` is `[Some(false), 0]`, then we don't care about row 2 since we know `p` only | ||
166 | //! matches values that row 2 doesn't. For row 1 however, we need to dig into the | ||
167 | //! arguments of `Some` to know whether some new value is covered. So we compute | ||
168 | //! `U([[true, _]], [false, 0])`. | ||
169 | //! | ||
170 | //! - If `p_1 == _`, then we look at the list of constructors that appear in the first component of | ||
171 | //! the rows of `P`: | ||
172 | //! - If there are some constructors that aren't present, then we might think that the | ||
173 | //! wildcard `_` is useful, since it covers those constructors that weren't covered | ||
174 | //! before. | ||
175 | //! That's almost correct, but only works if there were no wildcards in those first | ||
176 | //! components. So we need to check that `p` is useful with respect to the rows that | ||
177 | //! start with a wildcard, if there are any. This is where `D` comes in: | ||
178 | //! `U(P, p) := U(D(P), D(p))` | ||
179 | //! | ||
180 | //! For example, if `P` is: | ||
181 | //! ```text | ||
182 | //! [ | ||
183 | //! [_, true, _], | ||
184 | //! [None, false, 1], | ||
185 | //! ] | ||
186 | //! ``` | ||
187 | //! and `p` is `[_, false, _]`, the `Some` constructor doesn't appear in `P`. So if we | ||
188 | //! only had row 2, we'd know that `p` is useful. However row 1 starts with a | ||
189 | //! wildcard, so we need to check whether `U([[true, _]], [false, 1])`. | ||
190 | //! | ||
191 | //! - Otherwise, all possible constructors (for the relevant type) are present. In this | ||
192 | //! case we must check whether the wildcard pattern covers any unmatched value. For | ||
193 | //! that, we can think of the `_` pattern as a big OR-pattern that covers all | ||
194 | //! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for | ||
195 | //! example. The wildcard pattern is useful in this case if it is useful when | ||
196 | //! specialized to one of the possible constructors. So we compute: | ||
197 | //! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))` | ||
198 | //! | ||
199 | //! For example, if `P` is: | ||
200 | //! ```text | ||
201 | //! [ | ||
202 | //! [Some(true), _], | ||
203 | //! [None, false], | ||
204 | //! ] | ||
205 | //! ``` | ||
206 | //! and `p` is `[_, false]`, both `None` and `Some` constructors appear in the first | ||
207 | //! components of `P`. We will therefore try popping both constructors in turn: we | ||
208 | //! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]], | ||
209 | //! [false])` for the `None` constructor. The first case returns true, so we know that | ||
210 | //! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched | ||
211 | //! before. | ||
212 | //! | ||
213 | //! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately: | ||
214 | //! | ||
215 | //! ```text | ||
216 | //! U(P, p) := U(P, (r_1, p_2, .., p_n)) | ||
217 | //! || U(P, (r_2, p_2, .., p_n)) | ||
218 | //! ``` | ||
219 | use std::sync::Arc; | ||
220 | |||
221 | use arena::Idx; | ||
222 | use hir_def::{ | ||
223 | adt::VariantData, | ||
224 | body::Body, | ||
225 | expr::{Expr, Literal, Pat, PatId}, | ||
226 | AdtId, EnumVariantId, VariantId, | ||
227 | }; | ||
228 | use smallvec::{smallvec, SmallVec}; | ||
229 | |||
230 | use crate::{db::HirDatabase, ApplicationTy, InferenceResult, Ty, TypeCtor}; | ||
231 | |||
232 | #[derive(Debug, Clone, Copy)] | ||
233 | /// Either a pattern from the source code being analyzed, represented as | ||
234 | /// as `PatId`, or a `Wild` pattern which is created as an intermediate | ||
235 | /// step in the match checking algorithm and thus is not backed by a | ||
236 | /// real `PatId`. | ||
237 | /// | ||
238 | /// Note that it is totally valid for the `PatId` variant to contain | ||
239 | /// a `PatId` which resolves to a `Wild` pattern, if that wild pattern | ||
240 | /// exists in the source code being analyzed. | ||
241 | enum PatIdOrWild { | ||
242 | PatId(PatId), | ||
243 | Wild, | ||
244 | } | ||
245 | |||
246 | impl PatIdOrWild { | ||
247 | fn as_pat(self, cx: &MatchCheckCtx) -> Pat { | ||
248 | match self { | ||
249 | PatIdOrWild::PatId(id) => cx.body.pats[id].clone(), | ||
250 | PatIdOrWild::Wild => Pat::Wild, | ||
251 | } | ||
252 | } | ||
253 | |||
254 | fn as_id(self) -> Option<PatId> { | ||
255 | match self { | ||
256 | PatIdOrWild::PatId(id) => Some(id), | ||
257 | PatIdOrWild::Wild => None, | ||
258 | } | ||
259 | } | ||
260 | } | ||
261 | |||
262 | impl From<PatId> for PatIdOrWild { | ||
263 | fn from(pat_id: PatId) -> Self { | ||
264 | Self::PatId(pat_id) | ||
265 | } | ||
266 | } | ||
267 | |||
268 | impl From<&PatId> for PatIdOrWild { | ||
269 | fn from(pat_id: &PatId) -> Self { | ||
270 | Self::PatId(*pat_id) | ||
271 | } | ||
272 | } | ||
273 | |||
274 | #[derive(Debug, Clone, Copy, PartialEq)] | ||
275 | pub(super) enum MatchCheckErr { | ||
276 | NotImplemented, | ||
277 | MalformedMatchArm, | ||
278 | /// Used when type inference cannot resolve the type of | ||
279 | /// a pattern or expression. | ||
280 | Unknown, | ||
281 | } | ||
282 | |||
283 | /// The return type of `is_useful` is either an indication of usefulness | ||
284 | /// of the match arm, or an error in the case the match statement | ||
285 | /// is made up of types for which exhaustiveness checking is currently | ||
286 | /// not completely implemented. | ||
287 | /// | ||
288 | /// The `std::result::Result` type is used here rather than a custom enum | ||
289 | /// to allow the use of `?`. | ||
290 | pub(super) type MatchCheckResult<T> = Result<T, MatchCheckErr>; | ||
291 | |||
292 | #[derive(Debug)] | ||
293 | /// A row in a Matrix. | ||
294 | /// | ||
295 | /// This type is modeled from the struct of the same name in `rustc`. | ||
296 | pub(super) struct PatStack(PatStackInner); | ||
297 | type PatStackInner = SmallVec<[PatIdOrWild; 2]>; | ||
298 | |||
299 | impl PatStack { | ||
300 | pub(super) fn from_pattern(pat_id: PatId) -> PatStack { | ||
301 | Self(smallvec!(pat_id.into())) | ||
302 | } | ||
303 | |||
304 | pub(super) fn from_wild() -> PatStack { | ||
305 | Self(smallvec!(PatIdOrWild::Wild)) | ||
306 | } | ||
307 | |||
308 | fn from_slice(slice: &[PatIdOrWild]) -> PatStack { | ||
309 | Self(SmallVec::from_slice(slice)) | ||
310 | } | ||
311 | |||
312 | fn from_vec(v: PatStackInner) -> PatStack { | ||
313 | Self(v) | ||
314 | } | ||
315 | |||
316 | fn get_head(&self) -> Option<PatIdOrWild> { | ||
317 | self.0.first().copied() | ||
318 | } | ||
319 | |||
320 | fn tail(&self) -> &[PatIdOrWild] { | ||
321 | self.0.get(1..).unwrap_or(&[]) | ||
322 | } | ||
323 | |||
324 | fn to_tail(&self) -> PatStack { | ||
325 | Self::from_slice(self.tail()) | ||
326 | } | ||
327 | |||
328 | fn replace_head_with<I, T>(&self, pats: I) -> PatStack | ||
329 | where | ||
330 | I: Iterator<Item = T>, | ||
331 | T: Into<PatIdOrWild>, | ||
332 | { | ||
333 | let mut patterns: PatStackInner = smallvec![]; | ||
334 | for pat in pats { | ||
335 | patterns.push(pat.into()); | ||
336 | } | ||
337 | for pat in &self.0[1..] { | ||
338 | patterns.push(*pat); | ||
339 | } | ||
340 | PatStack::from_vec(patterns) | ||
341 | } | ||
342 | |||
343 | /// Computes `D(self)`. | ||
344 | /// | ||
345 | /// See the module docs and the associated documentation in rustc for details. | ||
346 | fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Option<PatStack> { | ||
347 | if matches!(self.get_head()?.as_pat(cx), Pat::Wild) { | ||
348 | Some(self.to_tail()) | ||
349 | } else { | ||
350 | None | ||
351 | } | ||
352 | } | ||
353 | |||
354 | /// Computes `S(constructor, self)`. | ||
355 | /// | ||
356 | /// See the module docs and the associated documentation in rustc for details. | ||
357 | fn specialize_constructor( | ||
358 | &self, | ||
359 | cx: &MatchCheckCtx, | ||
360 | constructor: &Constructor, | ||
361 | ) -> MatchCheckResult<Option<PatStack>> { | ||
362 | let head = match self.get_head() { | ||
363 | Some(head) => head, | ||
364 | None => return Ok(None), | ||
365 | }; | ||
366 | |||
367 | let head_pat = head.as_pat(cx); | ||
368 | let result = match (head_pat, constructor) { | ||
369 | (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => { | ||
370 | if ellipsis.is_some() { | ||
371 | // If there are ellipsis here, we should add the correct number of | ||
372 | // Pat::Wild patterns to `pat_ids`. We should be able to use the | ||
373 | // constructors arity for this, but at the time of writing we aren't | ||
374 | // correctly calculating this arity when ellipsis are present. | ||
375 | return Err(MatchCheckErr::NotImplemented); | ||
376 | } | ||
377 | |||
378 | Some(self.replace_head_with(pat_ids.iter())) | ||
379 | } | ||
380 | (Pat::Lit(lit_expr), Constructor::Bool(constructor_val)) => { | ||
381 | match cx.body.exprs[lit_expr] { | ||
382 | Expr::Literal(Literal::Bool(pat_val)) if *constructor_val == pat_val => { | ||
383 | Some(self.to_tail()) | ||
384 | } | ||
385 | // it was a bool but the value doesn't match | ||
386 | Expr::Literal(Literal::Bool(_)) => None, | ||
387 | // perhaps this is actually unreachable given we have | ||
388 | // already checked that these match arms have the appropriate type? | ||
389 | _ => return Err(MatchCheckErr::NotImplemented), | ||
390 | } | ||
391 | } | ||
392 | (Pat::Wild, constructor) => Some(self.expand_wildcard(cx, constructor)?), | ||
393 | (Pat::Path(_), Constructor::Enum(constructor)) => { | ||
394 | // unit enum variants become `Pat::Path` | ||
395 | let pat_id = head.as_id().expect("we know this isn't a wild"); | ||
396 | if !enum_variant_matches(cx, pat_id, *constructor) { | ||
397 | None | ||
398 | } else { | ||
399 | Some(self.to_tail()) | ||
400 | } | ||
401 | } | ||
402 | ( | ||
403 | Pat::TupleStruct { args: ref pat_ids, ellipsis, .. }, | ||
404 | Constructor::Enum(enum_constructor), | ||
405 | ) => { | ||
406 | let pat_id = head.as_id().expect("we know this isn't a wild"); | ||
407 | if !enum_variant_matches(cx, pat_id, *enum_constructor) { | ||
408 | None | ||
409 | } else { | ||
410 | let constructor_arity = constructor.arity(cx)?; | ||
411 | if let Some(ellipsis_position) = ellipsis { | ||
412 | // If there are ellipsis in the pattern, the ellipsis must take the place | ||
413 | // of at least one sub-pattern, so `pat_ids` should be smaller than the | ||
414 | // constructor arity. | ||
415 | if pat_ids.len() < constructor_arity { | ||
416 | let mut new_patterns: Vec<PatIdOrWild> = vec![]; | ||
417 | |||
418 | for pat_id in &pat_ids[0..ellipsis_position] { | ||
419 | new_patterns.push((*pat_id).into()); | ||
420 | } | ||
421 | |||
422 | for _ in 0..(constructor_arity - pat_ids.len()) { | ||
423 | new_patterns.push(PatIdOrWild::Wild); | ||
424 | } | ||
425 | |||
426 | for pat_id in &pat_ids[ellipsis_position..pat_ids.len()] { | ||
427 | new_patterns.push((*pat_id).into()); | ||
428 | } | ||
429 | |||
430 | Some(self.replace_head_with(new_patterns.into_iter())) | ||
431 | } else { | ||
432 | return Err(MatchCheckErr::MalformedMatchArm); | ||
433 | } | ||
434 | } else { | ||
435 | // If there is no ellipsis in the tuple pattern, the number | ||
436 | // of patterns must equal the constructor arity. | ||
437 | if pat_ids.len() == constructor_arity { | ||
438 | Some(self.replace_head_with(pat_ids.into_iter())) | ||
439 | } else { | ||
440 | return Err(MatchCheckErr::MalformedMatchArm); | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | (Pat::Record { args: ref arg_patterns, .. }, Constructor::Enum(e)) => { | ||
446 | let pat_id = head.as_id().expect("we know this isn't a wild"); | ||
447 | if !enum_variant_matches(cx, pat_id, *e) { | ||
448 | None | ||
449 | } else { | ||
450 | match cx.db.enum_data(e.parent).variants[e.local_id].variant_data.as_ref() { | ||
451 | VariantData::Record(struct_field_arena) => { | ||
452 | // Here we treat any missing fields in the record as the wild pattern, as | ||
453 | // if the record has ellipsis. We want to do this here even if the | ||
454 | // record does not contain ellipsis, because it allows us to continue | ||
455 | // enforcing exhaustiveness for the rest of the match statement. | ||
456 | // | ||
457 | // Creating the diagnostic for the missing field in the pattern | ||
458 | // should be done in a different diagnostic. | ||
459 | let patterns = struct_field_arena.iter().map(|(_, struct_field)| { | ||
460 | arg_patterns | ||
461 | .iter() | ||
462 | .find(|pat| pat.name == struct_field.name) | ||
463 | .map(|pat| PatIdOrWild::from(pat.pat)) | ||
464 | .unwrap_or(PatIdOrWild::Wild) | ||
465 | }); | ||
466 | |||
467 | Some(self.replace_head_with(patterns)) | ||
468 | } | ||
469 | _ => return Err(MatchCheckErr::Unknown), | ||
470 | } | ||
471 | } | ||
472 | } | ||
473 | (Pat::Or(_), _) => return Err(MatchCheckErr::NotImplemented), | ||
474 | (_, _) => return Err(MatchCheckErr::NotImplemented), | ||
475 | }; | ||
476 | |||
477 | Ok(result) | ||
478 | } | ||
479 | |||
480 | /// A special case of `specialize_constructor` where the head of the pattern stack | ||
481 | /// is a Wild pattern. | ||
482 | /// | ||
483 | /// Replaces the Wild pattern at the head of the pattern stack with N Wild patterns | ||
484 | /// (N >= 0), where N is the arity of the given constructor. | ||
485 | fn expand_wildcard( | ||
486 | &self, | ||
487 | cx: &MatchCheckCtx, | ||
488 | constructor: &Constructor, | ||
489 | ) -> MatchCheckResult<PatStack> { | ||
490 | assert_eq!( | ||
491 | Pat::Wild, | ||
492 | self.get_head().expect("expand_wildcard called on empty PatStack").as_pat(cx), | ||
493 | "expand_wildcard must only be called on PatStack with wild at head", | ||
494 | ); | ||
495 | |||
496 | let mut patterns: PatStackInner = smallvec![]; | ||
497 | |||
498 | for _ in 0..constructor.arity(cx)? { | ||
499 | patterns.push(PatIdOrWild::Wild); | ||
500 | } | ||
501 | |||
502 | for pat in &self.0[1..] { | ||
503 | patterns.push(*pat); | ||
504 | } | ||
505 | |||
506 | Ok(PatStack::from_vec(patterns)) | ||
507 | } | ||
508 | } | ||
509 | |||
510 | /// A collection of PatStack. | ||
511 | /// | ||
512 | /// This type is modeled from the struct of the same name in `rustc`. | ||
513 | pub(super) struct Matrix(Vec<PatStack>); | ||
514 | |||
515 | impl Matrix { | ||
516 | pub(super) fn empty() -> Self { | ||
517 | Self(vec![]) | ||
518 | } | ||
519 | |||
520 | pub(super) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) { | ||
521 | if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { | ||
522 | // Or patterns are expanded here | ||
523 | for pat_id in pat_ids { | ||
524 | self.0.push(PatStack::from_pattern(pat_id)); | ||
525 | } | ||
526 | } else { | ||
527 | self.0.push(row); | ||
528 | } | ||
529 | } | ||
530 | |||
531 | fn is_empty(&self) -> bool { | ||
532 | self.0.is_empty() | ||
533 | } | ||
534 | |||
535 | fn heads(&self) -> Vec<PatIdOrWild> { | ||
536 | self.0.iter().flat_map(|p| p.get_head()).collect() | ||
537 | } | ||
538 | |||
539 | /// Computes `D(self)` for each contained PatStack. | ||
540 | /// | ||
541 | /// See the module docs and the associated documentation in rustc for details. | ||
542 | fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Self { | ||
543 | Self::collect(cx, self.0.iter().filter_map(|r| r.specialize_wildcard(cx))) | ||
544 | } | ||
545 | |||
546 | /// Computes `S(constructor, self)` for each contained PatStack. | ||
547 | /// | ||
548 | /// See the module docs and the associated documentation in rustc for details. | ||
549 | fn specialize_constructor( | ||
550 | &self, | ||
551 | cx: &MatchCheckCtx, | ||
552 | constructor: &Constructor, | ||
553 | ) -> MatchCheckResult<Self> { | ||
554 | let mut new_matrix = Matrix::empty(); | ||
555 | for pat in &self.0 { | ||
556 | if let Some(pat) = pat.specialize_constructor(cx, constructor)? { | ||
557 | new_matrix.push(cx, pat); | ||
558 | } | ||
559 | } | ||
560 | |||
561 | Ok(new_matrix) | ||
562 | } | ||
563 | |||
564 | fn collect<T: IntoIterator<Item = PatStack>>(cx: &MatchCheckCtx, iter: T) -> Self { | ||
565 | let mut matrix = Matrix::empty(); | ||
566 | |||
567 | for pat in iter { | ||
568 | // using push ensures we expand or-patterns | ||
569 | matrix.push(cx, pat); | ||
570 | } | ||
571 | |||
572 | matrix | ||
573 | } | ||
574 | } | ||
575 | |||
576 | #[derive(Clone, Debug, PartialEq)] | ||
577 | /// An indication of the usefulness of a given match arm, where | ||
578 | /// usefulness is defined as matching some patterns which were | ||
579 | /// not matched by an prior match arms. | ||
580 | /// | ||
581 | /// We may eventually need an `Unknown` variant here. | ||
582 | pub(super) enum Usefulness { | ||
583 | Useful, | ||
584 | NotUseful, | ||
585 | } | ||
586 | |||
587 | pub(super) struct MatchCheckCtx<'a> { | ||
588 | pub(super) match_expr: Idx<Expr>, | ||
589 | pub(super) body: Arc<Body>, | ||
590 | pub(super) infer: Arc<InferenceResult>, | ||
591 | pub(super) db: &'a dyn HirDatabase, | ||
592 | } | ||
593 | |||
594 | /// Given a set of patterns `matrix`, and pattern to consider `v`, determines | ||
595 | /// whether `v` is useful. A pattern is useful if it covers cases which were | ||
596 | /// not previously covered. | ||
597 | /// | ||
598 | /// When calling this function externally (that is, not the recursive calls) it | ||
599 | /// expected that you have already type checked the match arms. All patterns in | ||
600 | /// matrix should be the same type as v, as well as they should all be the same | ||
601 | /// type as the match expression. | ||
602 | pub(super) fn is_useful( | ||
603 | cx: &MatchCheckCtx, | ||
604 | matrix: &Matrix, | ||
605 | v: &PatStack, | ||
606 | ) -> MatchCheckResult<Usefulness> { | ||
607 | // Handle two special cases: | ||
608 | // - enum with no variants | ||
609 | // - `!` type | ||
610 | // In those cases, no match arm is useful. | ||
611 | match cx.infer[cx.match_expr].strip_references() { | ||
612 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(AdtId::EnumId(enum_id)), .. }) => { | ||
613 | if cx.db.enum_data(*enum_id).variants.is_empty() { | ||
614 | return Ok(Usefulness::NotUseful); | ||
615 | } | ||
616 | } | ||
617 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) => { | ||
618 | return Ok(Usefulness::NotUseful); | ||
619 | } | ||
620 | _ => (), | ||
621 | } | ||
622 | |||
623 | let head = match v.get_head() { | ||
624 | Some(head) => head, | ||
625 | None => { | ||
626 | let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful }; | ||
627 | |||
628 | return Ok(result); | ||
629 | } | ||
630 | }; | ||
631 | |||
632 | if let Pat::Or(pat_ids) = head.as_pat(cx) { | ||
633 | let mut found_unimplemented = false; | ||
634 | let any_useful = pat_ids.iter().any(|&pat_id| { | ||
635 | let v = PatStack::from_pattern(pat_id); | ||
636 | |||
637 | match is_useful(cx, matrix, &v) { | ||
638 | Ok(Usefulness::Useful) => true, | ||
639 | Ok(Usefulness::NotUseful) => false, | ||
640 | _ => { | ||
641 | found_unimplemented = true; | ||
642 | false | ||
643 | } | ||
644 | } | ||
645 | }); | ||
646 | |||
647 | return if any_useful { | ||
648 | Ok(Usefulness::Useful) | ||
649 | } else if found_unimplemented { | ||
650 | Err(MatchCheckErr::NotImplemented) | ||
651 | } else { | ||
652 | Ok(Usefulness::NotUseful) | ||
653 | }; | ||
654 | } | ||
655 | |||
656 | if let Some(constructor) = pat_constructor(cx, head)? { | ||
657 | let matrix = matrix.specialize_constructor(&cx, &constructor)?; | ||
658 | let v = v | ||
659 | .specialize_constructor(&cx, &constructor)? | ||
660 | .expect("we know this can't fail because we get the constructor from `v.head()` above"); | ||
661 | |||
662 | is_useful(&cx, &matrix, &v) | ||
663 | } else { | ||
664 | // expanding wildcard | ||
665 | let mut used_constructors: Vec<Constructor> = vec![]; | ||
666 | for pat in matrix.heads() { | ||
667 | if let Some(constructor) = pat_constructor(cx, pat)? { | ||
668 | used_constructors.push(constructor); | ||
669 | } | ||
670 | } | ||
671 | |||
672 | // We assume here that the first constructor is the "correct" type. Since we | ||
673 | // only care about the "type" of the constructor (i.e. if it is a bool we | ||
674 | // don't care about the value), this assumption should be valid as long as | ||
675 | // the match statement is well formed. We currently uphold this invariant by | ||
676 | // filtering match arms before calling `is_useful`, only passing in match arms | ||
677 | // whose type matches the type of the match expression. | ||
678 | match &used_constructors.first() { | ||
679 | Some(constructor) if all_constructors_covered(&cx, constructor, &used_constructors) => { | ||
680 | // If all constructors are covered, then we need to consider whether | ||
681 | // any values are covered by this wildcard. | ||
682 | // | ||
683 | // For example, with matrix '[[Some(true)], [None]]', all | ||
684 | // constructors are covered (`Some`/`None`), so we need | ||
685 | // to perform specialization to see that our wildcard will cover | ||
686 | // the `Some(false)` case. | ||
687 | // | ||
688 | // Here we create a constructor for each variant and then check | ||
689 | // usefulness after specializing for that constructor. | ||
690 | let mut found_unimplemented = false; | ||
691 | for constructor in constructor.all_constructors(cx) { | ||
692 | let matrix = matrix.specialize_constructor(&cx, &constructor)?; | ||
693 | let v = v.expand_wildcard(&cx, &constructor)?; | ||
694 | |||
695 | match is_useful(&cx, &matrix, &v) { | ||
696 | Ok(Usefulness::Useful) => return Ok(Usefulness::Useful), | ||
697 | Ok(Usefulness::NotUseful) => continue, | ||
698 | _ => found_unimplemented = true, | ||
699 | }; | ||
700 | } | ||
701 | |||
702 | if found_unimplemented { | ||
703 | Err(MatchCheckErr::NotImplemented) | ||
704 | } else { | ||
705 | Ok(Usefulness::NotUseful) | ||
706 | } | ||
707 | } | ||
708 | _ => { | ||
709 | // Either not all constructors are covered, or the only other arms | ||
710 | // are wildcards. Either way, this pattern is useful if it is useful | ||
711 | // when compared to those arms with wildcards. | ||
712 | let matrix = matrix.specialize_wildcard(&cx); | ||
713 | let v = v.to_tail(); | ||
714 | |||
715 | is_useful(&cx, &matrix, &v) | ||
716 | } | ||
717 | } | ||
718 | } | ||
719 | } | ||
720 | |||
721 | #[derive(Debug, Clone, Copy)] | ||
722 | /// Similar to TypeCtor, but includes additional information about the specific | ||
723 | /// value being instantiated. For example, TypeCtor::Bool doesn't contain the | ||
724 | /// boolean value. | ||
725 | enum Constructor { | ||
726 | Bool(bool), | ||
727 | Tuple { arity: usize }, | ||
728 | Enum(EnumVariantId), | ||
729 | } | ||
730 | |||
731 | impl Constructor { | ||
732 | fn arity(&self, cx: &MatchCheckCtx) -> MatchCheckResult<usize> { | ||
733 | let arity = match self { | ||
734 | Constructor::Bool(_) => 0, | ||
735 | Constructor::Tuple { arity } => *arity, | ||
736 | Constructor::Enum(e) => { | ||
737 | match cx.db.enum_data(e.parent).variants[e.local_id].variant_data.as_ref() { | ||
738 | VariantData::Tuple(struct_field_data) => struct_field_data.len(), | ||
739 | VariantData::Record(struct_field_data) => struct_field_data.len(), | ||
740 | VariantData::Unit => 0, | ||
741 | } | ||
742 | } | ||
743 | }; | ||
744 | |||
745 | Ok(arity) | ||
746 | } | ||
747 | |||
748 | fn all_constructors(&self, cx: &MatchCheckCtx) -> Vec<Constructor> { | ||
749 | match self { | ||
750 | Constructor::Bool(_) => vec![Constructor::Bool(true), Constructor::Bool(false)], | ||
751 | Constructor::Tuple { .. } => vec![*self], | ||
752 | Constructor::Enum(e) => cx | ||
753 | .db | ||
754 | .enum_data(e.parent) | ||
755 | .variants | ||
756 | .iter() | ||
757 | .map(|(local_id, _)| { | ||
758 | Constructor::Enum(EnumVariantId { parent: e.parent, local_id }) | ||
759 | }) | ||
760 | .collect(), | ||
761 | } | ||
762 | } | ||
763 | } | ||
764 | |||
765 | /// Returns the constructor for the given pattern. Should only return None | ||
766 | /// in the case of a Wild pattern. | ||
767 | fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> { | ||
768 | let res = match pat.as_pat(cx) { | ||
769 | Pat::Wild => None, | ||
770 | // FIXME somehow create the Tuple constructor with the proper arity. If there are | ||
771 | // ellipsis, the arity is not equal to the number of patterns. | ||
772 | Pat::Tuple { args: pats, ellipsis } if ellipsis.is_none() => { | ||
773 | Some(Constructor::Tuple { arity: pats.len() }) | ||
774 | } | ||
775 | Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] { | ||
776 | Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)), | ||
777 | _ => return Err(MatchCheckErr::NotImplemented), | ||
778 | }, | ||
779 | Pat::TupleStruct { .. } | Pat::Path(_) | Pat::Record { .. } => { | ||
780 | let pat_id = pat.as_id().expect("we already know this pattern is not a wild"); | ||
781 | let variant_id = | ||
782 | cx.infer.variant_resolution_for_pat(pat_id).ok_or(MatchCheckErr::Unknown)?; | ||
783 | match variant_id { | ||
784 | VariantId::EnumVariantId(enum_variant_id) => { | ||
785 | Some(Constructor::Enum(enum_variant_id)) | ||
786 | } | ||
787 | _ => return Err(MatchCheckErr::NotImplemented), | ||
788 | } | ||
789 | } | ||
790 | _ => return Err(MatchCheckErr::NotImplemented), | ||
791 | }; | ||
792 | |||
793 | Ok(res) | ||
794 | } | ||
795 | |||
796 | fn all_constructors_covered( | ||
797 | cx: &MatchCheckCtx, | ||
798 | constructor: &Constructor, | ||
799 | used_constructors: &[Constructor], | ||
800 | ) -> bool { | ||
801 | match constructor { | ||
802 | Constructor::Tuple { arity } => { | ||
803 | used_constructors.iter().any(|constructor| match constructor { | ||
804 | Constructor::Tuple { arity: used_arity } => arity == used_arity, | ||
805 | _ => false, | ||
806 | }) | ||
807 | } | ||
808 | Constructor::Bool(_) => { | ||
809 | if used_constructors.is_empty() { | ||
810 | return false; | ||
811 | } | ||
812 | |||
813 | let covers_true = | ||
814 | used_constructors.iter().any(|c| matches!(c, Constructor::Bool(true))); | ||
815 | let covers_false = | ||
816 | used_constructors.iter().any(|c| matches!(c, Constructor::Bool(false))); | ||
817 | |||
818 | covers_true && covers_false | ||
819 | } | ||
820 | Constructor::Enum(e) => cx.db.enum_data(e.parent).variants.iter().all(|(id, _)| { | ||
821 | for constructor in used_constructors { | ||
822 | if let Constructor::Enum(e) = constructor { | ||
823 | if id == e.local_id { | ||
824 | return true; | ||
825 | } | ||
826 | } | ||
827 | } | ||
828 | |||
829 | false | ||
830 | }), | ||
831 | } | ||
832 | } | ||
833 | |||
834 | fn enum_variant_matches(cx: &MatchCheckCtx, pat_id: PatId, enum_variant_id: EnumVariantId) -> bool { | ||
835 | Some(enum_variant_id.into()) == cx.infer.variant_resolution_for_pat(pat_id) | ||
836 | } | ||
837 | |||
838 | #[cfg(test)] | ||
839 | mod tests { | ||
840 | use crate::diagnostics::tests::check_diagnostics; | ||
841 | |||
842 | #[test] | ||
843 | fn empty_tuple() { | ||
844 | check_diagnostics( | ||
845 | r#" | ||
846 | fn main() { | ||
847 | match () { } | ||
848 | //^^ Missing match arm | ||
849 | match (()) { } | ||
850 | //^^^^ Missing match arm | ||
851 | |||
852 | match () { _ => (), } | ||
853 | match () { () => (), } | ||
854 | match (()) { (()) => (), } | ||
855 | } | ||
856 | "#, | ||
857 | ); | ||
858 | } | ||
859 | |||
860 | #[test] | ||
861 | fn tuple_of_two_empty_tuple() { | ||
862 | check_diagnostics( | ||
863 | r#" | ||
864 | fn main() { | ||
865 | match ((), ()) { } | ||
866 | //^^^^^^^^ Missing match arm | ||
867 | |||
868 | match ((), ()) { ((), ()) => (), } | ||
869 | } | ||
870 | "#, | ||
871 | ); | ||
872 | } | ||
873 | |||
874 | #[test] | ||
875 | fn boolean() { | ||
876 | check_diagnostics( | ||
877 | r#" | ||
878 | fn test_main() { | ||
879 | match false { } | ||
880 | //^^^^^ Missing match arm | ||
881 | match false { true => (), } | ||
882 | //^^^^^ Missing match arm | ||
883 | match (false, true) {} | ||
884 | //^^^^^^^^^^^^^ Missing match arm | ||
885 | match (false, true) { (true, true) => (), } | ||
886 | //^^^^^^^^^^^^^ Missing match arm | ||
887 | match (false, true) { | ||
888 | //^^^^^^^^^^^^^ Missing match arm | ||
889 | (false, true) => (), | ||
890 | (false, false) => (), | ||
891 | (true, false) => (), | ||
892 | } | ||
893 | match (false, true) { (true, _x) => (), } | ||
894 | //^^^^^^^^^^^^^ Missing match arm | ||
895 | |||
896 | match false { true => (), false => (), } | ||
897 | match (false, true) { | ||
898 | (false, _) => (), | ||
899 | (true, false) => (), | ||
900 | (_, true) => (), | ||
901 | } | ||
902 | match (false, true) { | ||
903 | (true, true) => (), | ||
904 | (true, false) => (), | ||
905 | (false, true) => (), | ||
906 | (false, false) => (), | ||
907 | } | ||
908 | match (false, true) { | ||
909 | (true, _x) => (), | ||
910 | (false, true) => (), | ||
911 | (false, false) => (), | ||
912 | } | ||
913 | match (false, true, false) { | ||
914 | (false, ..) => (), | ||
915 | (true, ..) => (), | ||
916 | } | ||
917 | match (false, true, false) { | ||
918 | (.., false) => (), | ||
919 | (.., true) => (), | ||
920 | } | ||
921 | match (false, true, false) { (..) => (), } | ||
922 | } | ||
923 | "#, | ||
924 | ); | ||
925 | } | ||
926 | |||
927 | #[test] | ||
928 | fn tuple_of_tuple_and_bools() { | ||
929 | check_diagnostics( | ||
930 | r#" | ||
931 | fn main() { | ||
932 | match (false, ((), false)) {} | ||
933 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
934 | match (false, ((), false)) { (true, ((), true)) => (), } | ||
935 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
936 | match (false, ((), false)) { (true, _) => (), } | ||
937 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
938 | |||
939 | match (false, ((), false)) { | ||
940 | (true, ((), true)) => (), | ||
941 | (true, ((), false)) => (), | ||
942 | (false, ((), true)) => (), | ||
943 | (false, ((), false)) => (), | ||
944 | } | ||
945 | match (false, ((), false)) { | ||
946 | (true, ((), true)) => (), | ||
947 | (true, ((), false)) => (), | ||
948 | (false, _) => (), | ||
949 | } | ||
950 | } | ||
951 | "#, | ||
952 | ); | ||
953 | } | ||
954 | |||
955 | #[test] | ||
956 | fn enums() { | ||
957 | check_diagnostics( | ||
958 | r#" | ||
959 | enum Either { A, B, } | ||
960 | |||
961 | fn main() { | ||
962 | match Either::A { } | ||
963 | //^^^^^^^^^ Missing match arm | ||
964 | match Either::B { Either::A => (), } | ||
965 | //^^^^^^^^^ Missing match arm | ||
966 | |||
967 | match &Either::B { | ||
968 | //^^^^^^^^^^ Missing match arm | ||
969 | Either::A => (), | ||
970 | } | ||
971 | |||
972 | match Either::B { | ||
973 | Either::A => (), Either::B => (), | ||
974 | } | ||
975 | match &Either::B { | ||
976 | Either::A => (), Either::B => (), | ||
977 | } | ||
978 | } | ||
979 | "#, | ||
980 | ); | ||
981 | } | ||
982 | |||
983 | #[test] | ||
984 | fn enum_containing_bool() { | ||
985 | check_diagnostics( | ||
986 | r#" | ||
987 | enum Either { A(bool), B } | ||
988 | |||
989 | fn main() { | ||
990 | match Either::B { } | ||
991 | //^^^^^^^^^ Missing match arm | ||
992 | match Either::B { | ||
993 | //^^^^^^^^^ Missing match arm | ||
994 | Either::A(true) => (), Either::B => () | ||
995 | } | ||
996 | |||
997 | match Either::B { | ||
998 | Either::A(true) => (), | ||
999 | Either::A(false) => (), | ||
1000 | Either::B => (), | ||
1001 | } | ||
1002 | match Either::B { | ||
1003 | Either::B => (), | ||
1004 | _ => (), | ||
1005 | } | ||
1006 | match Either::B { | ||
1007 | Either::A(_) => (), | ||
1008 | Either::B => (), | ||
1009 | } | ||
1010 | |||
1011 | } | ||
1012 | "#, | ||
1013 | ); | ||
1014 | } | ||
1015 | |||
1016 | #[test] | ||
1017 | fn enum_different_sizes() { | ||
1018 | check_diagnostics( | ||
1019 | r#" | ||
1020 | enum Either { A(bool), B(bool, bool) } | ||
1021 | |||
1022 | fn main() { | ||
1023 | match Either::A(false) { | ||
1024 | //^^^^^^^^^^^^^^^^ Missing match arm | ||
1025 | Either::A(_) => (), | ||
1026 | Either::B(false, _) => (), | ||
1027 | } | ||
1028 | |||
1029 | match Either::A(false) { | ||
1030 | Either::A(_) => (), | ||
1031 | Either::B(true, _) => (), | ||
1032 | Either::B(false, _) => (), | ||
1033 | } | ||
1034 | match Either::A(false) { | ||
1035 | Either::A(true) | Either::A(false) => (), | ||
1036 | Either::B(true, _) => (), | ||
1037 | Either::B(false, _) => (), | ||
1038 | } | ||
1039 | } | ||
1040 | "#, | ||
1041 | ); | ||
1042 | } | ||
1043 | |||
1044 | #[test] | ||
1045 | fn tuple_of_enum_no_diagnostic() { | ||
1046 | check_diagnostics( | ||
1047 | r#" | ||
1048 | enum Either { A(bool), B(bool, bool) } | ||
1049 | enum Either2 { C, D } | ||
1050 | |||
1051 | fn main() { | ||
1052 | match (Either::A(false), Either2::C) { | ||
1053 | (Either::A(true), _) | (Either::A(false), _) => (), | ||
1054 | (Either::B(true, _), Either2::C) => (), | ||
1055 | (Either::B(false, _), Either2::C) => (), | ||
1056 | (Either::B(_, _), Either2::D) => (), | ||
1057 | } | ||
1058 | } | ||
1059 | "#, | ||
1060 | ); | ||
1061 | } | ||
1062 | |||
1063 | #[test] | ||
1064 | fn mismatched_types() { | ||
1065 | // Match statements with arms that don't match the | ||
1066 | // expression pattern do not fire this diagnostic. | ||
1067 | check_diagnostics( | ||
1068 | r#" | ||
1069 | enum Either { A, B } | ||
1070 | enum Either2 { C, D } | ||
1071 | |||
1072 | fn main() { | ||
1073 | match Either::A { | ||
1074 | Either2::C => (), | ||
1075 | Either2::D => (), | ||
1076 | } | ||
1077 | match (true, false) { | ||
1078 | (true, false, true) => (), | ||
1079 | (true) => (), | ||
1080 | } | ||
1081 | match (0) { () => () } | ||
1082 | match Unresolved::Bar { Unresolved::Baz => () } | ||
1083 | } | ||
1084 | "#, | ||
1085 | ); | ||
1086 | } | ||
1087 | |||
1088 | #[test] | ||
1089 | fn malformed_match_arm_tuple_enum_missing_pattern() { | ||
1090 | // We are testing to be sure we don't panic here when the match | ||
1091 | // arm `Either::B` is missing its pattern. | ||
1092 | check_diagnostics( | ||
1093 | r#" | ||
1094 | enum Either { A, B(u32) } | ||
1095 | |||
1096 | fn main() { | ||
1097 | match Either::A { | ||
1098 | Either::A => (), | ||
1099 | Either::B() => (), | ||
1100 | } | ||
1101 | } | ||
1102 | "#, | ||
1103 | ); | ||
1104 | } | ||
1105 | |||
1106 | #[test] | ||
1107 | fn expr_diverges() { | ||
1108 | check_diagnostics( | ||
1109 | r#" | ||
1110 | enum Either { A, B } | ||
1111 | |||
1112 | fn main() { | ||
1113 | match loop {} { | ||
1114 | Either::A => (), | ||
1115 | Either::B => (), | ||
1116 | } | ||
1117 | match loop {} { | ||
1118 | Either::A => (), | ||
1119 | } | ||
1120 | match loop { break Foo::A } { | ||
1121 | //^^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1122 | Either::A => (), | ||
1123 | } | ||
1124 | match loop { break Foo::A } { | ||
1125 | Either::A => (), | ||
1126 | Either::B => (), | ||
1127 | } | ||
1128 | } | ||
1129 | "#, | ||
1130 | ); | ||
1131 | } | ||
1132 | |||
1133 | #[test] | ||
1134 | fn expr_partially_diverges() { | ||
1135 | check_diagnostics( | ||
1136 | r#" | ||
1137 | enum Either<T> { A(T), B } | ||
1138 | |||
1139 | fn foo() -> Either<!> { Either::B } | ||
1140 | fn main() -> u32 { | ||
1141 | match foo() { | ||
1142 | Either::A(val) => val, | ||
1143 | Either::B => 0, | ||
1144 | } | ||
1145 | } | ||
1146 | "#, | ||
1147 | ); | ||
1148 | } | ||
1149 | |||
1150 | #[test] | ||
1151 | fn enum_record() { | ||
1152 | check_diagnostics( | ||
1153 | r#" | ||
1154 | enum Either { A { foo: bool }, B } | ||
1155 | |||
1156 | fn main() { | ||
1157 | let a = Either::A { foo: true }; | ||
1158 | match a { } | ||
1159 | //^ Missing match arm | ||
1160 | match a { Either::A { foo: true } => () } | ||
1161 | //^ Missing match arm | ||
1162 | match a { | ||
1163 | Either::A { } => (), | ||
1164 | //^^^^^^^^^ Missing structure fields: | ||
1165 | // | - foo | ||
1166 | Either::B => (), | ||
1167 | } | ||
1168 | match a { | ||
1169 | //^ Missing match arm | ||
1170 | Either::A { } => (), | ||
1171 | } //^^^^^^^^^ Missing structure fields: | ||
1172 | // | - foo | ||
1173 | |||
1174 | match a { | ||
1175 | Either::A { foo: true } => (), | ||
1176 | Either::A { foo: false } => (), | ||
1177 | Either::B => (), | ||
1178 | } | ||
1179 | match a { | ||
1180 | Either::A { foo: _ } => (), | ||
1181 | Either::B => (), | ||
1182 | } | ||
1183 | } | ||
1184 | "#, | ||
1185 | ); | ||
1186 | } | ||
1187 | |||
1188 | #[test] | ||
1189 | fn enum_record_fields_out_of_order() { | ||
1190 | check_diagnostics( | ||
1191 | r#" | ||
1192 | enum Either { | ||
1193 | A { foo: bool, bar: () }, | ||
1194 | B, | ||
1195 | } | ||
1196 | |||
1197 | fn main() { | ||
1198 | let a = Either::A { foo: true, bar: () }; | ||
1199 | match a { | ||
1200 | //^ Missing match arm | ||
1201 | Either::A { bar: (), foo: false } => (), | ||
1202 | Either::A { foo: true, bar: () } => (), | ||
1203 | } | ||
1204 | |||
1205 | match a { | ||
1206 | Either::A { bar: (), foo: false } => (), | ||
1207 | Either::A { foo: true, bar: () } => (), | ||
1208 | Either::B => (), | ||
1209 | } | ||
1210 | } | ||
1211 | "#, | ||
1212 | ); | ||
1213 | } | ||
1214 | |||
1215 | #[test] | ||
1216 | fn enum_record_ellipsis() { | ||
1217 | check_diagnostics( | ||
1218 | r#" | ||
1219 | enum Either { | ||
1220 | A { foo: bool, bar: bool }, | ||
1221 | B, | ||
1222 | } | ||
1223 | |||
1224 | fn main() { | ||
1225 | let a = Either::B; | ||
1226 | match a { | ||
1227 | //^ Missing match arm | ||
1228 | Either::A { foo: true, .. } => (), | ||
1229 | Either::B => (), | ||
1230 | } | ||
1231 | match a { | ||
1232 | //^ Missing match arm | ||
1233 | Either::A { .. } => (), | ||
1234 | } | ||
1235 | |||
1236 | match a { | ||
1237 | Either::A { foo: true, .. } => (), | ||
1238 | Either::A { foo: false, .. } => (), | ||
1239 | Either::B => (), | ||
1240 | } | ||
1241 | |||
1242 | match a { | ||
1243 | Either::A { .. } => (), | ||
1244 | Either::B => (), | ||
1245 | } | ||
1246 | } | ||
1247 | "#, | ||
1248 | ); | ||
1249 | } | ||
1250 | |||
1251 | #[test] | ||
1252 | fn enum_tuple_partial_ellipsis() { | ||
1253 | check_diagnostics( | ||
1254 | r#" | ||
1255 | enum Either { | ||
1256 | A(bool, bool, bool, bool), | ||
1257 | B, | ||
1258 | } | ||
1259 | |||
1260 | fn main() { | ||
1261 | match Either::B { | ||
1262 | //^^^^^^^^^ Missing match arm | ||
1263 | Either::A(true, .., true) => (), | ||
1264 | Either::A(true, .., false) => (), | ||
1265 | Either::A(false, .., false) => (), | ||
1266 | Either::B => (), | ||
1267 | } | ||
1268 | match Either::B { | ||
1269 | //^^^^^^^^^ Missing match arm | ||
1270 | Either::A(true, .., true) => (), | ||
1271 | Either::A(true, .., false) => (), | ||
1272 | Either::A(.., true) => (), | ||
1273 | Either::B => (), | ||
1274 | } | ||
1275 | |||
1276 | match Either::B { | ||
1277 | Either::A(true, .., true) => (), | ||
1278 | Either::A(true, .., false) => (), | ||
1279 | Either::A(false, .., true) => (), | ||
1280 | Either::A(false, .., false) => (), | ||
1281 | Either::B => (), | ||
1282 | } | ||
1283 | match Either::B { | ||
1284 | Either::A(true, .., true) => (), | ||
1285 | Either::A(true, .., false) => (), | ||
1286 | Either::A(.., true) => (), | ||
1287 | Either::A(.., false) => (), | ||
1288 | Either::B => (), | ||
1289 | } | ||
1290 | } | ||
1291 | "#, | ||
1292 | ); | ||
1293 | } | ||
1294 | |||
1295 | #[test] | ||
1296 | fn never() { | ||
1297 | check_diagnostics( | ||
1298 | r#" | ||
1299 | enum Never {} | ||
1300 | |||
1301 | fn enum_(never: Never) { | ||
1302 | match never {} | ||
1303 | } | ||
1304 | fn enum_ref(never: &Never) { | ||
1305 | match never {} | ||
1306 | } | ||
1307 | fn bang(never: !) { | ||
1308 | match never {} | ||
1309 | } | ||
1310 | "#, | ||
1311 | ); | ||
1312 | } | ||
1313 | |||
1314 | #[test] | ||
1315 | fn or_pattern_panic() { | ||
1316 | check_diagnostics( | ||
1317 | r#" | ||
1318 | pub enum Category { Infinity, Zero } | ||
1319 | |||
1320 | fn panic(a: Category, b: Category) { | ||
1321 | match (a, b) { | ||
1322 | (Category::Zero | Category::Infinity, _) => (), | ||
1323 | (_, Category::Zero | Category::Infinity) => (), | ||
1324 | } | ||
1325 | |||
1326 | // FIXME: This is a false positive, but the code used to cause a panic in the match checker, | ||
1327 | // so this acts as a regression test for that. | ||
1328 | match (a, b) { | ||
1329 | //^^^^^^ Missing match arm | ||
1330 | (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => (), | ||
1331 | (Category::Infinity | Category::Zero, _) => (), | ||
1332 | } | ||
1333 | } | ||
1334 | "#, | ||
1335 | ); | ||
1336 | } | ||
1337 | |||
1338 | #[test] | ||
1339 | fn unknown_type() { | ||
1340 | check_diagnostics( | ||
1341 | r#" | ||
1342 | enum Option<T> { Some(T), None } | ||
1343 | |||
1344 | fn main() { | ||
1345 | // `Never` is deliberately not defined so that it's an uninferred type. | ||
1346 | match Option::<Never>::None { | ||
1347 | None => (), | ||
1348 | Some(never) => match never {}, | ||
1349 | } | ||
1350 | } | ||
1351 | "#, | ||
1352 | ); | ||
1353 | } | ||
1354 | |||
1355 | mod false_negatives { | ||
1356 | //! The implementation of match checking here is a work in progress. As we roll this out, we | ||
1357 | //! prefer false negatives to false positives (ideally there would be no false positives). This | ||
1358 | //! test module should document known false negatives. Eventually we will have a complete | ||
1359 | //! implementation of match checking and this module will be empty. | ||
1360 | //! | ||
1361 | //! The reasons for documenting known false negatives: | ||
1362 | //! | ||
1363 | //! 1. It acts as a backlog of work that can be done to improve the behavior of the system. | ||
1364 | //! 2. It ensures the code doesn't panic when handling these cases. | ||
1365 | use super::*; | ||
1366 | |||
1367 | #[test] | ||
1368 | fn integers() { | ||
1369 | // We don't currently check integer exhaustiveness. | ||
1370 | check_diagnostics( | ||
1371 | r#" | ||
1372 | fn main() { | ||
1373 | match 5 { | ||
1374 | 10 => (), | ||
1375 | 11..20 => (), | ||
1376 | } | ||
1377 | } | ||
1378 | "#, | ||
1379 | ); | ||
1380 | } | ||
1381 | |||
1382 | #[test] | ||
1383 | fn internal_or() { | ||
1384 | // We do not currently handle patterns with internal `or`s. | ||
1385 | check_diagnostics( | ||
1386 | r#" | ||
1387 | fn main() { | ||
1388 | enum Either { A(bool), B } | ||
1389 | match Either::B { | ||
1390 | Either::A(true | false) => (), | ||
1391 | } | ||
1392 | } | ||
1393 | "#, | ||
1394 | ); | ||
1395 | } | ||
1396 | |||
1397 | #[test] | ||
1398 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | ||
1399 | // We don't currently handle tuple patterns with ellipsis. | ||
1400 | check_diagnostics( | ||
1401 | r#" | ||
1402 | fn main() { | ||
1403 | match (false, true, false) { | ||
1404 | (false, ..) => (), | ||
1405 | } | ||
1406 | } | ||
1407 | "#, | ||
1408 | ); | ||
1409 | } | ||
1410 | |||
1411 | #[test] | ||
1412 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | ||
1413 | // We don't currently handle tuple patterns with ellipsis. | ||
1414 | check_diagnostics( | ||
1415 | r#" | ||
1416 | fn main() { | ||
1417 | match (false, true, false) { | ||
1418 | (.., false) => (), | ||
1419 | } | ||
1420 | } | ||
1421 | "#, | ||
1422 | ); | ||
1423 | } | ||
1424 | |||
1425 | #[test] | ||
1426 | fn struct_missing_arm() { | ||
1427 | // We don't currently handle structs. | ||
1428 | check_diagnostics( | ||
1429 | r#" | ||
1430 | struct Foo { a: bool } | ||
1431 | fn main(f: Foo) { | ||
1432 | match f { Foo { a: true } => () } | ||
1433 | } | ||
1434 | "#, | ||
1435 | ); | ||
1436 | } | ||
1437 | } | ||
1438 | } | ||
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs new file mode 100644 index 000000000..61ffbf5d1 --- /dev/null +++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs | |||
@@ -0,0 +1,205 @@ | |||
1 | //! Provides validations for unsafe code. Currently checks if unsafe functions are missing | ||
2 | //! unsafe blocks. | ||
3 | |||
4 | use std::sync::Arc; | ||
5 | |||
6 | use hir_def::{ | ||
7 | body::Body, | ||
8 | expr::{Expr, ExprId, UnaryOp}, | ||
9 | resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, | ||
10 | DefWithBodyId, | ||
11 | }; | ||
12 | use hir_expand::diagnostics::DiagnosticSink; | ||
13 | |||
14 | use crate::{ | ||
15 | db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDefId, ApplicationTy, | ||
16 | InferenceResult, Ty, TypeCtor, | ||
17 | }; | ||
18 | |||
19 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { | ||
20 | owner: DefWithBodyId, | ||
21 | infer: Arc<InferenceResult>, | ||
22 | sink: &'a mut DiagnosticSink<'b>, | ||
23 | } | ||
24 | |||
25 | impl<'a, 'b> UnsafeValidator<'a, 'b> { | ||
26 | pub(super) fn new( | ||
27 | owner: DefWithBodyId, | ||
28 | infer: Arc<InferenceResult>, | ||
29 | sink: &'a mut DiagnosticSink<'b>, | ||
30 | ) -> UnsafeValidator<'a, 'b> { | ||
31 | UnsafeValidator { owner, infer, sink } | ||
32 | } | ||
33 | |||
34 | pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { | ||
35 | let def = self.owner.into(); | ||
36 | let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); | ||
37 | let is_unsafe = match self.owner { | ||
38 | DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe, | ||
39 | DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, | ||
40 | }; | ||
41 | if is_unsafe | ||
42 | || unsafe_expressions | ||
43 | .iter() | ||
44 | .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block) | ||
45 | .count() | ||
46 | == 0 | ||
47 | { | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | let (_, body_source) = db.body_with_source_map(def); | ||
52 | for unsafe_expr in unsafe_expressions { | ||
53 | if !unsafe_expr.inside_unsafe_block { | ||
54 | if let Ok(in_file) = body_source.as_ref().expr_syntax(unsafe_expr.expr) { | ||
55 | self.sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | } | ||
61 | |||
62 | pub struct UnsafeExpr { | ||
63 | pub expr: ExprId, | ||
64 | pub inside_unsafe_block: bool, | ||
65 | } | ||
66 | |||
67 | pub fn unsafe_expressions( | ||
68 | db: &dyn HirDatabase, | ||
69 | infer: &InferenceResult, | ||
70 | def: DefWithBodyId, | ||
71 | ) -> Vec<UnsafeExpr> { | ||
72 | let mut unsafe_exprs = vec![]; | ||
73 | let body = db.body(def); | ||
74 | walk_unsafe(&mut unsafe_exprs, db, infer, def, &body, body.body_expr, false); | ||
75 | |||
76 | unsafe_exprs | ||
77 | } | ||
78 | |||
79 | fn walk_unsafe( | ||
80 | unsafe_exprs: &mut Vec<UnsafeExpr>, | ||
81 | db: &dyn HirDatabase, | ||
82 | infer: &InferenceResult, | ||
83 | def: DefWithBodyId, | ||
84 | body: &Body, | ||
85 | current: ExprId, | ||
86 | inside_unsafe_block: bool, | ||
87 | ) { | ||
88 | let expr = &body.exprs[current]; | ||
89 | match expr { | ||
90 | Expr::Call { callee, .. } => { | ||
91 | let ty = &infer[*callee]; | ||
92 | if let &Ty::Apply(ApplicationTy { | ||
93 | ctor: TypeCtor::FnDef(CallableDefId::FunctionId(func)), | ||
94 | .. | ||
95 | }) = ty | ||
96 | { | ||
97 | if db.function_data(func).is_unsafe { | ||
98 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | Expr::Path(path) => { | ||
103 | let resolver = resolver_for_expr(db.upcast(), def, current); | ||
104 | let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path()); | ||
105 | if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial { | ||
106 | if db.static_data(id).mutable { | ||
107 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | Expr::MethodCall { .. } => { | ||
112 | if infer | ||
113 | .method_resolution(current) | ||
114 | .map(|func| db.function_data(func).is_unsafe) | ||
115 | .unwrap_or(false) | ||
116 | { | ||
117 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); | ||
118 | } | ||
119 | } | ||
120 | Expr::UnaryOp { expr, op: UnaryOp::Deref } => { | ||
121 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }) = &infer[*expr] { | ||
122 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); | ||
123 | } | ||
124 | } | ||
125 | Expr::Unsafe { body: child } => { | ||
126 | return walk_unsafe(unsafe_exprs, db, infer, def, body, *child, true); | ||
127 | } | ||
128 | _ => {} | ||
129 | } | ||
130 | |||
131 | expr.walk_child_exprs(|child| { | ||
132 | walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block); | ||
133 | }); | ||
134 | } | ||
135 | |||
136 | #[cfg(test)] | ||
137 | mod tests { | ||
138 | use crate::diagnostics::tests::check_diagnostics; | ||
139 | |||
140 | #[test] | ||
141 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
142 | check_diagnostics( | ||
143 | r#" | ||
144 | fn main() { | ||
145 | let x = &5 as *const usize; | ||
146 | unsafe { let y = *x; } | ||
147 | let z = *x; | ||
148 | } //^^ This operation is unsafe and requires an unsafe function or block | ||
149 | "#, | ||
150 | ) | ||
151 | } | ||
152 | |||
153 | #[test] | ||
154 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
155 | check_diagnostics( | ||
156 | r#" | ||
157 | struct HasUnsafe; | ||
158 | |||
159 | impl HasUnsafe { | ||
160 | unsafe fn unsafe_fn(&self) { | ||
161 | let x = &5 as *const usize; | ||
162 | let y = *x; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | unsafe fn unsafe_fn() { | ||
167 | let x = &5 as *const usize; | ||
168 | let y = *x; | ||
169 | } | ||
170 | |||
171 | fn main() { | ||
172 | unsafe_fn(); | ||
173 | //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
174 | HasUnsafe.unsafe_fn(); | ||
175 | //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
176 | unsafe { | ||
177 | unsafe_fn(); | ||
178 | HasUnsafe.unsafe_fn(); | ||
179 | } | ||
180 | } | ||
181 | "#, | ||
182 | ); | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn missing_unsafe_diagnostic_with_static_mut() { | ||
187 | check_diagnostics( | ||
188 | r#" | ||
189 | struct Ty { | ||
190 | a: u8, | ||
191 | } | ||
192 | |||
193 | static mut static_mut: Ty = Ty { a: 0 }; | ||
194 | |||
195 | fn main() { | ||
196 | let x = static_mut.a; | ||
197 | //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
198 | unsafe { | ||
199 | let x = static_mut.a; | ||
200 | } | ||
201 | } | ||
202 | "#, | ||
203 | ); | ||
204 | } | ||
205 | } | ||
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs new file mode 100644 index 000000000..64b68014d --- /dev/null +++ b/crates/hir_ty/src/display.rs | |||
@@ -0,0 +1,632 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::fmt; | ||
4 | |||
5 | use crate::{ | ||
6 | db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate, | ||
7 | Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | ||
8 | }; | ||
9 | use hir_def::{ | ||
10 | find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId, | ||
11 | Lookup, ModuleId, | ||
12 | }; | ||
13 | use hir_expand::name::Name; | ||
14 | |||
15 | pub struct HirFormatter<'a> { | ||
16 | pub db: &'a dyn HirDatabase, | ||
17 | fmt: &'a mut dyn fmt::Write, | ||
18 | buf: String, | ||
19 | curr_size: usize, | ||
20 | pub(crate) max_size: Option<usize>, | ||
21 | omit_verbose_types: bool, | ||
22 | display_target: DisplayTarget, | ||
23 | } | ||
24 | |||
25 | pub trait HirDisplay { | ||
26 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError>; | ||
27 | |||
28 | /// Returns a `Display`able type that is human-readable. | ||
29 | /// Use this for showing types to the user (e.g. diagnostics) | ||
30 | fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self> | ||
31 | where | ||
32 | Self: Sized, | ||
33 | { | ||
34 | HirDisplayWrapper { | ||
35 | db, | ||
36 | t: self, | ||
37 | max_size: None, | ||
38 | omit_verbose_types: false, | ||
39 | display_target: DisplayTarget::Diagnostics, | ||
40 | } | ||
41 | } | ||
42 | |||
43 | /// Returns a `Display`able type that is human-readable and tries to be succinct. | ||
44 | /// Use this for showing types to the user where space is constrained (e.g. doc popups) | ||
45 | fn display_truncated<'a>( | ||
46 | &'a self, | ||
47 | db: &'a dyn HirDatabase, | ||
48 | max_size: Option<usize>, | ||
49 | ) -> HirDisplayWrapper<'a, Self> | ||
50 | where | ||
51 | Self: Sized, | ||
52 | { | ||
53 | HirDisplayWrapper { | ||
54 | db, | ||
55 | t: self, | ||
56 | max_size, | ||
57 | omit_verbose_types: true, | ||
58 | display_target: DisplayTarget::Diagnostics, | ||
59 | } | ||
60 | } | ||
61 | |||
62 | /// Returns a String representation of `self` that can be inserted into the given module. | ||
63 | /// Use this when generating code (e.g. assists) | ||
64 | fn display_source_code<'a>( | ||
65 | &'a self, | ||
66 | db: &'a dyn HirDatabase, | ||
67 | module_id: ModuleId, | ||
68 | ) -> Result<String, DisplaySourceCodeError> { | ||
69 | let mut result = String::new(); | ||
70 | match self.hir_fmt(&mut HirFormatter { | ||
71 | db, | ||
72 | fmt: &mut result, | ||
73 | buf: String::with_capacity(20), | ||
74 | curr_size: 0, | ||
75 | max_size: None, | ||
76 | omit_verbose_types: false, | ||
77 | display_target: DisplayTarget::SourceCode { module_id }, | ||
78 | }) { | ||
79 | Ok(()) => {} | ||
80 | Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"), | ||
81 | Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e), | ||
82 | }; | ||
83 | Ok(result) | ||
84 | } | ||
85 | } | ||
86 | |||
87 | impl<'a> HirFormatter<'a> { | ||
88 | pub fn write_joined<T: HirDisplay>( | ||
89 | &mut self, | ||
90 | iter: impl IntoIterator<Item = T>, | ||
91 | sep: &str, | ||
92 | ) -> Result<(), HirDisplayError> { | ||
93 | let mut first = true; | ||
94 | for e in iter { | ||
95 | if !first { | ||
96 | write!(self, "{}", sep)?; | ||
97 | } | ||
98 | first = false; | ||
99 | e.hir_fmt(self)?; | ||
100 | } | ||
101 | Ok(()) | ||
102 | } | ||
103 | |||
104 | /// This allows using the `write!` macro directly with a `HirFormatter`. | ||
105 | pub fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), HirDisplayError> { | ||
106 | // We write to a buffer first to track output size | ||
107 | self.buf.clear(); | ||
108 | fmt::write(&mut self.buf, args)?; | ||
109 | self.curr_size += self.buf.len(); | ||
110 | |||
111 | // Then we write to the internal formatter from the buffer | ||
112 | self.fmt.write_str(&self.buf).map_err(HirDisplayError::from) | ||
113 | } | ||
114 | |||
115 | pub fn should_truncate(&self) -> bool { | ||
116 | if let Some(max_size) = self.max_size { | ||
117 | self.curr_size >= max_size | ||
118 | } else { | ||
119 | false | ||
120 | } | ||
121 | } | ||
122 | |||
123 | pub fn omit_verbose_types(&self) -> bool { | ||
124 | self.omit_verbose_types | ||
125 | } | ||
126 | } | ||
127 | |||
128 | #[derive(Clone, Copy)] | ||
129 | enum DisplayTarget { | ||
130 | /// Display types for inlays, doc popups, autocompletion, etc... | ||
131 | /// Showing `{unknown}` or not qualifying paths is fine here. | ||
132 | /// There's no reason for this to fail. | ||
133 | Diagnostics, | ||
134 | /// Display types for inserting them in source files. | ||
135 | /// The generated code should compile, so paths need to be qualified. | ||
136 | SourceCode { module_id: ModuleId }, | ||
137 | } | ||
138 | |||
139 | impl DisplayTarget { | ||
140 | fn is_source_code(&self) -> bool { | ||
141 | matches!(self, Self::SourceCode {..}) | ||
142 | } | ||
143 | } | ||
144 | |||
145 | #[derive(Debug)] | ||
146 | pub enum DisplaySourceCodeError { | ||
147 | PathNotFound, | ||
148 | } | ||
149 | |||
150 | pub enum HirDisplayError { | ||
151 | /// Errors that can occur when generating source code | ||
152 | DisplaySourceCodeError(DisplaySourceCodeError), | ||
153 | /// `FmtError` is required to be compatible with std::fmt::Display | ||
154 | FmtError, | ||
155 | } | ||
156 | impl From<fmt::Error> for HirDisplayError { | ||
157 | fn from(_: fmt::Error) -> Self { | ||
158 | Self::FmtError | ||
159 | } | ||
160 | } | ||
161 | |||
162 | pub struct HirDisplayWrapper<'a, T> { | ||
163 | db: &'a dyn HirDatabase, | ||
164 | t: &'a T, | ||
165 | max_size: Option<usize>, | ||
166 | omit_verbose_types: bool, | ||
167 | display_target: DisplayTarget, | ||
168 | } | ||
169 | |||
170 | impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T> | ||
171 | where | ||
172 | T: HirDisplay, | ||
173 | { | ||
174 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
175 | match self.t.hir_fmt(&mut HirFormatter { | ||
176 | db: self.db, | ||
177 | fmt: f, | ||
178 | buf: String::with_capacity(20), | ||
179 | curr_size: 0, | ||
180 | max_size: self.max_size, | ||
181 | omit_verbose_types: self.omit_verbose_types, | ||
182 | display_target: self.display_target, | ||
183 | }) { | ||
184 | Ok(()) => Ok(()), | ||
185 | Err(HirDisplayError::FmtError) => Err(fmt::Error), | ||
186 | Err(HirDisplayError::DisplaySourceCodeError(_)) => { | ||
187 | // This should never happen | ||
188 | panic!("HirDisplay failed when calling Display::fmt!") | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | |||
194 | const TYPE_HINT_TRUNCATION: &str = "…"; | ||
195 | |||
196 | impl HirDisplay for &Ty { | ||
197 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
198 | HirDisplay::hir_fmt(*self, f) | ||
199 | } | ||
200 | } | ||
201 | |||
202 | impl HirDisplay for ApplicationTy { | ||
203 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
204 | if f.should_truncate() { | ||
205 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
206 | } | ||
207 | |||
208 | match self.ctor { | ||
209 | TypeCtor::Bool => write!(f, "bool")?, | ||
210 | TypeCtor::Char => write!(f, "char")?, | ||
211 | TypeCtor::Int(t) => write!(f, "{}", t)?, | ||
212 | TypeCtor::Float(t) => write!(f, "{}", t)?, | ||
213 | TypeCtor::Str => write!(f, "str")?, | ||
214 | TypeCtor::Slice => { | ||
215 | let t = self.parameters.as_single(); | ||
216 | write!(f, "[{}]", t.display(f.db))?; | ||
217 | } | ||
218 | TypeCtor::Array => { | ||
219 | let t = self.parameters.as_single(); | ||
220 | write!(f, "[{}; _]", t.display(f.db))?; | ||
221 | } | ||
222 | TypeCtor::RawPtr(m) => { | ||
223 | let t = self.parameters.as_single(); | ||
224 | write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?; | ||
225 | } | ||
226 | TypeCtor::Ref(m) => { | ||
227 | let t = self.parameters.as_single(); | ||
228 | let ty_display = if f.omit_verbose_types() { | ||
229 | t.display_truncated(f.db, f.max_size) | ||
230 | } else { | ||
231 | t.display(f.db) | ||
232 | }; | ||
233 | write!(f, "&{}{}", m.as_keyword_for_ref(), ty_display)?; | ||
234 | } | ||
235 | TypeCtor::Never => write!(f, "!")?, | ||
236 | TypeCtor::Tuple { .. } => { | ||
237 | let ts = &self.parameters; | ||
238 | if ts.len() == 1 { | ||
239 | write!(f, "({},)", ts[0].display(f.db))?; | ||
240 | } else { | ||
241 | write!(f, "(")?; | ||
242 | f.write_joined(&*ts.0, ", ")?; | ||
243 | write!(f, ")")?; | ||
244 | } | ||
245 | } | ||
246 | TypeCtor::FnPtr { is_varargs, .. } => { | ||
247 | let sig = FnSig::from_fn_ptr_substs(&self.parameters, is_varargs); | ||
248 | write!(f, "fn(")?; | ||
249 | f.write_joined(sig.params(), ", ")?; | ||
250 | if is_varargs { | ||
251 | if sig.params().is_empty() { | ||
252 | write!(f, "...")?; | ||
253 | } else { | ||
254 | write!(f, ", ...")?; | ||
255 | } | ||
256 | } | ||
257 | write!(f, ")")?; | ||
258 | let ret = sig.ret(); | ||
259 | if *ret != Ty::unit() { | ||
260 | let ret_display = if f.omit_verbose_types() { | ||
261 | ret.display_truncated(f.db, f.max_size) | ||
262 | } else { | ||
263 | ret.display(f.db) | ||
264 | }; | ||
265 | write!(f, " -> {}", ret_display)?; | ||
266 | } | ||
267 | } | ||
268 | TypeCtor::FnDef(def) => { | ||
269 | let sig = f.db.callable_item_signature(def).subst(&self.parameters); | ||
270 | match def { | ||
271 | CallableDefId::FunctionId(ff) => { | ||
272 | write!(f, "fn {}", f.db.function_data(ff).name)? | ||
273 | } | ||
274 | CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?, | ||
275 | CallableDefId::EnumVariantId(e) => { | ||
276 | write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)? | ||
277 | } | ||
278 | }; | ||
279 | if self.parameters.len() > 0 { | ||
280 | let generics = generics(f.db.upcast(), def.into()); | ||
281 | let (parent_params, self_param, type_params, _impl_trait_params) = | ||
282 | generics.provenance_split(); | ||
283 | let total_len = parent_params + self_param + type_params; | ||
284 | // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? | ||
285 | if total_len > 0 { | ||
286 | write!(f, "<")?; | ||
287 | f.write_joined(&self.parameters.0[..total_len], ", ")?; | ||
288 | write!(f, ">")?; | ||
289 | } | ||
290 | } | ||
291 | write!(f, "(")?; | ||
292 | f.write_joined(sig.params(), ", ")?; | ||
293 | write!(f, ")")?; | ||
294 | let ret = sig.ret(); | ||
295 | if *ret != Ty::unit() { | ||
296 | let ret_display = if f.omit_verbose_types() { | ||
297 | ret.display_truncated(f.db, f.max_size) | ||
298 | } else { | ||
299 | ret.display(f.db) | ||
300 | }; | ||
301 | write!(f, " -> {}", ret_display)?; | ||
302 | } | ||
303 | } | ||
304 | TypeCtor::Adt(def_id) => { | ||
305 | match f.display_target { | ||
306 | DisplayTarget::Diagnostics => { | ||
307 | let name = match def_id { | ||
308 | AdtId::StructId(it) => f.db.struct_data(it).name.clone(), | ||
309 | AdtId::UnionId(it) => f.db.union_data(it).name.clone(), | ||
310 | AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), | ||
311 | }; | ||
312 | write!(f, "{}", name)?; | ||
313 | } | ||
314 | DisplayTarget::SourceCode { module_id } => { | ||
315 | if let Some(path) = find_path::find_path( | ||
316 | f.db.upcast(), | ||
317 | ItemInNs::Types(def_id.into()), | ||
318 | module_id, | ||
319 | ) { | ||
320 | write!(f, "{}", path)?; | ||
321 | } else { | ||
322 | return Err(HirDisplayError::DisplaySourceCodeError( | ||
323 | DisplaySourceCodeError::PathNotFound, | ||
324 | )); | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | if self.parameters.len() > 0 { | ||
330 | let parameters_to_write = | ||
331 | if f.display_target.is_source_code() || f.omit_verbose_types() { | ||
332 | match self | ||
333 | .ctor | ||
334 | .as_generic_def() | ||
335 | .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) | ||
336 | .filter(|defaults| !defaults.is_empty()) | ||
337 | { | ||
338 | None => self.parameters.0.as_ref(), | ||
339 | Some(default_parameters) => { | ||
340 | let mut default_from = 0; | ||
341 | for (i, parameter) in self.parameters.iter().enumerate() { | ||
342 | match (parameter, default_parameters.get(i)) { | ||
343 | (&Ty::Unknown, _) | (_, None) => { | ||
344 | default_from = i + 1; | ||
345 | } | ||
346 | (_, Some(default_parameter)) => { | ||
347 | let actual_default = default_parameter | ||
348 | .clone() | ||
349 | .subst(&self.parameters.prefix(i)); | ||
350 | if parameter != &actual_default { | ||
351 | default_from = i + 1; | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | } | ||
356 | &self.parameters.0[0..default_from] | ||
357 | } | ||
358 | } | ||
359 | } else { | ||
360 | self.parameters.0.as_ref() | ||
361 | }; | ||
362 | if !parameters_to_write.is_empty() { | ||
363 | write!(f, "<")?; | ||
364 | f.write_joined(parameters_to_write, ", ")?; | ||
365 | write!(f, ">")?; | ||
366 | } | ||
367 | } | ||
368 | } | ||
369 | TypeCtor::AssociatedType(type_alias) => { | ||
370 | let trait_ = match type_alias.lookup(f.db.upcast()).container { | ||
371 | AssocContainerId::TraitId(it) => it, | ||
372 | _ => panic!("not an associated type"), | ||
373 | }; | ||
374 | let trait_ = f.db.trait_data(trait_); | ||
375 | let type_alias = f.db.type_alias_data(type_alias); | ||
376 | write!(f, "{}::{}", trait_.name, type_alias.name)?; | ||
377 | if self.parameters.len() > 0 { | ||
378 | write!(f, "<")?; | ||
379 | f.write_joined(&*self.parameters.0, ", ")?; | ||
380 | write!(f, ">")?; | ||
381 | } | ||
382 | } | ||
383 | TypeCtor::OpaqueType(opaque_ty_id) => { | ||
384 | let bounds = match opaque_ty_id { | ||
385 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | ||
386 | let datas = | ||
387 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); | ||
388 | let data = (*datas) | ||
389 | .as_ref() | ||
390 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | ||
391 | data.subst(&self.parameters) | ||
392 | } | ||
393 | }; | ||
394 | write!(f, "impl ")?; | ||
395 | write_bounds_like_dyn_trait(&bounds.value, f)?; | ||
396 | // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution | ||
397 | } | ||
398 | TypeCtor::Closure { .. } => { | ||
399 | let sig = self.parameters[0].callable_sig(f.db); | ||
400 | if let Some(sig) = sig { | ||
401 | if sig.params().is_empty() { | ||
402 | write!(f, "||")?; | ||
403 | } else if f.omit_verbose_types() { | ||
404 | write!(f, "|{}|", TYPE_HINT_TRUNCATION)?; | ||
405 | } else { | ||
406 | write!(f, "|")?; | ||
407 | f.write_joined(sig.params(), ", ")?; | ||
408 | write!(f, "|")?; | ||
409 | }; | ||
410 | |||
411 | let ret_display = if f.omit_verbose_types() { | ||
412 | sig.ret().display_truncated(f.db, f.max_size) | ||
413 | } else { | ||
414 | sig.ret().display(f.db) | ||
415 | }; | ||
416 | write!(f, " -> {}", ret_display)?; | ||
417 | } else { | ||
418 | write!(f, "{{closure}}")?; | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | Ok(()) | ||
423 | } | ||
424 | } | ||
425 | |||
426 | impl HirDisplay for ProjectionTy { | ||
427 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
428 | if f.should_truncate() { | ||
429 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
430 | } | ||
431 | |||
432 | let trait_ = f.db.trait_data(self.trait_(f.db)); | ||
433 | write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_.name)?; | ||
434 | if self.parameters.len() > 1 { | ||
435 | write!(f, "<")?; | ||
436 | f.write_joined(&self.parameters[1..], ", ")?; | ||
437 | write!(f, ">")?; | ||
438 | } | ||
439 | write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?; | ||
440 | Ok(()) | ||
441 | } | ||
442 | } | ||
443 | |||
444 | impl HirDisplay for Ty { | ||
445 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
446 | if f.should_truncate() { | ||
447 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
448 | } | ||
449 | |||
450 | match self { | ||
451 | Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, | ||
452 | Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, | ||
453 | Ty::Placeholder(id) => { | ||
454 | let generics = generics(f.db.upcast(), id.parent); | ||
455 | let param_data = &generics.params.types[id.local_id]; | ||
456 | match param_data.provenance { | ||
457 | TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { | ||
458 | write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? | ||
459 | } | ||
460 | TypeParamProvenance::ArgumentImplTrait => { | ||
461 | write!(f, "impl ")?; | ||
462 | let bounds = f.db.generic_predicates_for_param(*id); | ||
463 | let substs = Substs::type_params_for_generics(&generics); | ||
464 | write_bounds_like_dyn_trait( | ||
465 | &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(), | ||
466 | f, | ||
467 | )?; | ||
468 | } | ||
469 | } | ||
470 | } | ||
471 | Ty::Bound(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?, | ||
472 | Ty::Dyn(predicates) => { | ||
473 | write!(f, "dyn ")?; | ||
474 | write_bounds_like_dyn_trait(predicates, f)?; | ||
475 | } | ||
476 | Ty::Opaque(opaque_ty) => { | ||
477 | let bounds = match opaque_ty.opaque_ty_id { | ||
478 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | ||
479 | let datas = | ||
480 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); | ||
481 | let data = (*datas) | ||
482 | .as_ref() | ||
483 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | ||
484 | data.subst(&opaque_ty.parameters) | ||
485 | } | ||
486 | }; | ||
487 | write!(f, "impl ")?; | ||
488 | write_bounds_like_dyn_trait(&bounds.value, f)?; | ||
489 | } | ||
490 | Ty::Unknown => write!(f, "{{unknown}}")?, | ||
491 | Ty::Infer(..) => write!(f, "_")?, | ||
492 | } | ||
493 | Ok(()) | ||
494 | } | ||
495 | } | ||
496 | |||
497 | fn write_bounds_like_dyn_trait( | ||
498 | predicates: &[GenericPredicate], | ||
499 | f: &mut HirFormatter, | ||
500 | ) -> Result<(), HirDisplayError> { | ||
501 | // Note: This code is written to produce nice results (i.e. | ||
502 | // corresponding to surface Rust) for types that can occur in | ||
503 | // actual Rust. It will have weird results if the predicates | ||
504 | // aren't as expected (i.e. self types = $0, projection | ||
505 | // predicates for a certain trait come after the Implemented | ||
506 | // predicate for that trait). | ||
507 | let mut first = true; | ||
508 | let mut angle_open = false; | ||
509 | for p in predicates.iter() { | ||
510 | match p { | ||
511 | GenericPredicate::Implemented(trait_ref) => { | ||
512 | if angle_open { | ||
513 | write!(f, ">")?; | ||
514 | angle_open = false; | ||
515 | } | ||
516 | if !first { | ||
517 | write!(f, " + ")?; | ||
518 | } | ||
519 | // We assume that the self type is $0 (i.e. the | ||
520 | // existential) here, which is the only thing that's | ||
521 | // possible in actual Rust, and hence don't print it | ||
522 | write!(f, "{}", f.db.trait_data(trait_ref.trait_).name)?; | ||
523 | if trait_ref.substs.len() > 1 { | ||
524 | write!(f, "<")?; | ||
525 | f.write_joined(&trait_ref.substs[1..], ", ")?; | ||
526 | // there might be assoc type bindings, so we leave the angle brackets open | ||
527 | angle_open = true; | ||
528 | } | ||
529 | } | ||
530 | GenericPredicate::Projection(projection_pred) => { | ||
531 | // in types in actual Rust, these will always come | ||
532 | // after the corresponding Implemented predicate | ||
533 | if angle_open { | ||
534 | write!(f, ", ")?; | ||
535 | } else { | ||
536 | write!(f, "<")?; | ||
537 | angle_open = true; | ||
538 | } | ||
539 | let type_alias = f.db.type_alias_data(projection_pred.projection_ty.associated_ty); | ||
540 | write!(f, "{} = ", type_alias.name)?; | ||
541 | projection_pred.ty.hir_fmt(f)?; | ||
542 | } | ||
543 | GenericPredicate::Error => { | ||
544 | if angle_open { | ||
545 | // impl Trait<X, {error}> | ||
546 | write!(f, ", ")?; | ||
547 | } else if !first { | ||
548 | // impl Trait + {error} | ||
549 | write!(f, " + ")?; | ||
550 | } | ||
551 | p.hir_fmt(f)?; | ||
552 | } | ||
553 | } | ||
554 | first = false; | ||
555 | } | ||
556 | if angle_open { | ||
557 | write!(f, ">")?; | ||
558 | } | ||
559 | Ok(()) | ||
560 | } | ||
561 | |||
562 | impl TraitRef { | ||
563 | fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> { | ||
564 | if f.should_truncate() { | ||
565 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
566 | } | ||
567 | |||
568 | self.substs[0].hir_fmt(f)?; | ||
569 | if use_as { | ||
570 | write!(f, " as ")?; | ||
571 | } else { | ||
572 | write!(f, ": ")?; | ||
573 | } | ||
574 | write!(f, "{}", f.db.trait_data(self.trait_).name)?; | ||
575 | if self.substs.len() > 1 { | ||
576 | write!(f, "<")?; | ||
577 | f.write_joined(&self.substs[1..], ", ")?; | ||
578 | write!(f, ">")?; | ||
579 | } | ||
580 | Ok(()) | ||
581 | } | ||
582 | } | ||
583 | |||
584 | impl HirDisplay for TraitRef { | ||
585 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
586 | self.hir_fmt_ext(f, false) | ||
587 | } | ||
588 | } | ||
589 | |||
590 | impl HirDisplay for &GenericPredicate { | ||
591 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
592 | HirDisplay::hir_fmt(*self, f) | ||
593 | } | ||
594 | } | ||
595 | |||
596 | impl HirDisplay for GenericPredicate { | ||
597 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
598 | if f.should_truncate() { | ||
599 | return write!(f, "{}", TYPE_HINT_TRUNCATION); | ||
600 | } | ||
601 | |||
602 | match self { | ||
603 | GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, | ||
604 | GenericPredicate::Projection(projection_pred) => { | ||
605 | write!(f, "<")?; | ||
606 | projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; | ||
607 | write!( | ||
608 | f, | ||
609 | ">::{} = {}", | ||
610 | f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name, | ||
611 | projection_pred.ty.display(f.db) | ||
612 | )?; | ||
613 | } | ||
614 | GenericPredicate::Error => write!(f, "{{error}}")?, | ||
615 | } | ||
616 | Ok(()) | ||
617 | } | ||
618 | } | ||
619 | |||
620 | impl HirDisplay for Obligation { | ||
621 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
622 | Ok(match self { | ||
623 | Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db))?, | ||
624 | Obligation::Projection(proj) => write!( | ||
625 | f, | ||
626 | "Normalize({} => {})", | ||
627 | proj.projection_ty.display(f.db), | ||
628 | proj.ty.display(f.db) | ||
629 | )?, | ||
630 | }) | ||
631 | } | ||
632 | } | ||
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs new file mode 100644 index 000000000..03b00b101 --- /dev/null +++ b/crates/hir_ty/src/infer.rs | |||
@@ -0,0 +1,802 @@ | |||
1 | //! Type inference, i.e. the process of walking through the code and determining | ||
2 | //! the type of each expression and pattern. | ||
3 | //! | ||
4 | //! For type inference, compare the implementations in rustc (the various | ||
5 | //! check_* methods in librustc_typeck/check/mod.rs are a good entry point) and | ||
6 | //! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for | ||
7 | //! inference here is the `infer` function, which infers the types of all | ||
8 | //! expressions in a given function. | ||
9 | //! | ||
10 | //! During inference, types (i.e. the `Ty` struct) can contain type 'variables' | ||
11 | //! which represent currently unknown types; as we walk through the expressions, | ||
12 | //! we might determine that certain variables need to be equal to each other, or | ||
13 | //! to certain types. To record this, we use the union-find implementation from | ||
14 | //! the `ena` crate, which is extracted from rustc. | ||
15 | |||
16 | use std::borrow::Cow; | ||
17 | use std::mem; | ||
18 | use std::ops::Index; | ||
19 | use std::sync::Arc; | ||
20 | |||
21 | use arena::map::ArenaMap; | ||
22 | use hir_def::{ | ||
23 | body::Body, | ||
24 | data::{ConstData, FunctionData, StaticData}, | ||
25 | expr::{BindingAnnotation, ExprId, PatId}, | ||
26 | lang_item::LangItemTarget, | ||
27 | path::{path, Path}, | ||
28 | resolver::{HasResolver, Resolver, TypeNs}, | ||
29 | type_ref::{Mutability, TypeRef}, | ||
30 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, Lookup, TraitId, | ||
31 | TypeAliasId, VariantId, | ||
32 | }; | ||
33 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; | ||
34 | use rustc_hash::FxHashMap; | ||
35 | use stdx::impl_from; | ||
36 | use syntax::SmolStr; | ||
37 | |||
38 | use super::{ | ||
39 | primitive::{FloatTy, IntTy}, | ||
40 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, | ||
41 | InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, | ||
42 | }; | ||
43 | use crate::{ | ||
44 | db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, | ||
45 | }; | ||
46 | |||
47 | pub(crate) use unify::unify; | ||
48 | |||
49 | macro_rules! ty_app { | ||
50 | ($ctor:pat, $param:pat) => { | ||
51 | crate::Ty::Apply(crate::ApplicationTy { ctor: $ctor, parameters: $param }) | ||
52 | }; | ||
53 | ($ctor:pat) => { | ||
54 | ty_app!($ctor, _) | ||
55 | }; | ||
56 | } | ||
57 | |||
58 | mod unify; | ||
59 | mod path; | ||
60 | mod expr; | ||
61 | mod pat; | ||
62 | mod coerce; | ||
63 | |||
64 | /// The entry point of type inference. | ||
65 | pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { | ||
66 | let _p = profile::span("infer_query"); | ||
67 | let resolver = def.resolver(db.upcast()); | ||
68 | let mut ctx = InferenceContext::new(db, def, resolver); | ||
69 | |||
70 | match def { | ||
71 | DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)), | ||
72 | DefWithBodyId::FunctionId(f) => ctx.collect_fn(&db.function_data(f)), | ||
73 | DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)), | ||
74 | } | ||
75 | |||
76 | ctx.infer_body(); | ||
77 | |||
78 | Arc::new(ctx.resolve_all()) | ||
79 | } | ||
80 | |||
81 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | ||
82 | enum ExprOrPatId { | ||
83 | ExprId(ExprId), | ||
84 | PatId(PatId), | ||
85 | } | ||
86 | impl_from!(ExprId, PatId for ExprOrPatId); | ||
87 | |||
88 | /// Binding modes inferred for patterns. | ||
89 | /// https://doc.rust-lang.org/reference/patterns.html#binding-modes | ||
90 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||
91 | enum BindingMode { | ||
92 | Move, | ||
93 | Ref(Mutability), | ||
94 | } | ||
95 | |||
96 | impl BindingMode { | ||
97 | pub fn convert(annotation: BindingAnnotation) -> BindingMode { | ||
98 | match annotation { | ||
99 | BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move, | ||
100 | BindingAnnotation::Ref => BindingMode::Ref(Mutability::Shared), | ||
101 | BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut), | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | |||
106 | impl Default for BindingMode { | ||
107 | fn default() -> Self { | ||
108 | BindingMode::Move | ||
109 | } | ||
110 | } | ||
111 | |||
112 | /// A mismatch between an expected and an inferred type. | ||
113 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
114 | pub struct TypeMismatch { | ||
115 | pub expected: Ty, | ||
116 | pub actual: Ty, | ||
117 | } | ||
118 | |||
119 | /// The result of type inference: A mapping from expressions and patterns to types. | ||
120 | #[derive(Clone, PartialEq, Eq, Debug, Default)] | ||
121 | pub struct InferenceResult { | ||
122 | /// For each method call expr, records the function it resolves to. | ||
123 | method_resolutions: FxHashMap<ExprId, FunctionId>, | ||
124 | /// For each field access expr, records the field it resolves to. | ||
125 | field_resolutions: FxHashMap<ExprId, FieldId>, | ||
126 | /// For each field in record literal, records the field it resolves to. | ||
127 | record_field_resolutions: FxHashMap<ExprId, FieldId>, | ||
128 | record_field_pat_resolutions: FxHashMap<PatId, FieldId>, | ||
129 | /// For each struct literal, records the variant it resolves to. | ||
130 | variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, | ||
131 | /// For each associated item record what it resolves to | ||
132 | assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>, | ||
133 | diagnostics: Vec<InferenceDiagnostic>, | ||
134 | pub type_of_expr: ArenaMap<ExprId, Ty>, | ||
135 | pub type_of_pat: ArenaMap<PatId, Ty>, | ||
136 | pub(super) type_mismatches: ArenaMap<ExprId, TypeMismatch>, | ||
137 | } | ||
138 | |||
139 | impl InferenceResult { | ||
140 | pub fn method_resolution(&self, expr: ExprId) -> Option<FunctionId> { | ||
141 | self.method_resolutions.get(&expr).copied() | ||
142 | } | ||
143 | pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> { | ||
144 | self.field_resolutions.get(&expr).copied() | ||
145 | } | ||
146 | pub fn record_field_resolution(&self, expr: ExprId) -> Option<FieldId> { | ||
147 | self.record_field_resolutions.get(&expr).copied() | ||
148 | } | ||
149 | pub fn record_field_pat_resolution(&self, pat: PatId) -> Option<FieldId> { | ||
150 | self.record_field_pat_resolutions.get(&pat).copied() | ||
151 | } | ||
152 | pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> { | ||
153 | self.variant_resolutions.get(&id.into()).copied() | ||
154 | } | ||
155 | pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> { | ||
156 | self.variant_resolutions.get(&id.into()).copied() | ||
157 | } | ||
158 | pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItemId> { | ||
159 | self.assoc_resolutions.get(&id.into()).copied() | ||
160 | } | ||
161 | pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItemId> { | ||
162 | self.assoc_resolutions.get(&id.into()).copied() | ||
163 | } | ||
164 | pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> { | ||
165 | self.type_mismatches.get(expr) | ||
166 | } | ||
167 | pub fn add_diagnostics( | ||
168 | &self, | ||
169 | db: &dyn HirDatabase, | ||
170 | owner: DefWithBodyId, | ||
171 | sink: &mut DiagnosticSink, | ||
172 | ) { | ||
173 | self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink)) | ||
174 | } | ||
175 | } | ||
176 | |||
177 | impl Index<ExprId> for InferenceResult { | ||
178 | type Output = Ty; | ||
179 | |||
180 | fn index(&self, expr: ExprId) -> &Ty { | ||
181 | self.type_of_expr.get(expr).unwrap_or(&Ty::Unknown) | ||
182 | } | ||
183 | } | ||
184 | |||
185 | impl Index<PatId> for InferenceResult { | ||
186 | type Output = Ty; | ||
187 | |||
188 | fn index(&self, pat: PatId) -> &Ty { | ||
189 | self.type_of_pat.get(pat).unwrap_or(&Ty::Unknown) | ||
190 | } | ||
191 | } | ||
192 | |||
193 | /// The inference context contains all information needed during type inference. | ||
194 | #[derive(Clone, Debug)] | ||
195 | struct InferenceContext<'a> { | ||
196 | db: &'a dyn HirDatabase, | ||
197 | owner: DefWithBodyId, | ||
198 | body: Arc<Body>, | ||
199 | resolver: Resolver, | ||
200 | table: unify::InferenceTable, | ||
201 | trait_env: Arc<TraitEnvironment>, | ||
202 | obligations: Vec<Obligation>, | ||
203 | result: InferenceResult, | ||
204 | /// The return type of the function being inferred, or the closure if we're | ||
205 | /// currently within one. | ||
206 | /// | ||
207 | /// We might consider using a nested inference context for checking | ||
208 | /// closures, but currently this is the only field that will change there, | ||
209 | /// so it doesn't make sense. | ||
210 | return_ty: Ty, | ||
211 | diverges: Diverges, | ||
212 | breakables: Vec<BreakableContext>, | ||
213 | } | ||
214 | |||
215 | #[derive(Clone, Debug)] | ||
216 | struct BreakableContext { | ||
217 | pub may_break: bool, | ||
218 | pub break_ty: Ty, | ||
219 | pub label: Option<name::Name>, | ||
220 | } | ||
221 | |||
222 | fn find_breakable<'c>( | ||
223 | ctxs: &'c mut [BreakableContext], | ||
224 | label: Option<&name::Name>, | ||
225 | ) -> Option<&'c mut BreakableContext> { | ||
226 | match label { | ||
227 | Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label), | ||
228 | None => ctxs.last_mut(), | ||
229 | } | ||
230 | } | ||
231 | |||
232 | impl<'a> InferenceContext<'a> { | ||
233 | fn new(db: &'a dyn HirDatabase, owner: DefWithBodyId, resolver: Resolver) -> Self { | ||
234 | InferenceContext { | ||
235 | result: InferenceResult::default(), | ||
236 | table: unify::InferenceTable::new(), | ||
237 | obligations: Vec::default(), | ||
238 | return_ty: Ty::Unknown, // set in collect_fn_signature | ||
239 | trait_env: TraitEnvironment::lower(db, &resolver), | ||
240 | db, | ||
241 | owner, | ||
242 | body: db.body(owner), | ||
243 | resolver, | ||
244 | diverges: Diverges::Maybe, | ||
245 | breakables: Vec::new(), | ||
246 | } | ||
247 | } | ||
248 | |||
249 | fn resolve_all(mut self) -> InferenceResult { | ||
250 | // FIXME resolve obligations as well (use Guidance if necessary) | ||
251 | let mut result = std::mem::take(&mut self.result); | ||
252 | for ty in result.type_of_expr.values_mut() { | ||
253 | let resolved = self.table.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); | ||
254 | *ty = resolved; | ||
255 | } | ||
256 | for ty in result.type_of_pat.values_mut() { | ||
257 | let resolved = self.table.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); | ||
258 | *ty = resolved; | ||
259 | } | ||
260 | result | ||
261 | } | ||
262 | |||
263 | fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) { | ||
264 | self.result.type_of_expr.insert(expr, ty); | ||
265 | } | ||
266 | |||
267 | fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId) { | ||
268 | self.result.method_resolutions.insert(expr, func); | ||
269 | } | ||
270 | |||
271 | fn write_field_resolution(&mut self, expr: ExprId, field: FieldId) { | ||
272 | self.result.field_resolutions.insert(expr, field); | ||
273 | } | ||
274 | |||
275 | fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) { | ||
276 | self.result.variant_resolutions.insert(id, variant); | ||
277 | } | ||
278 | |||
279 | fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId) { | ||
280 | self.result.assoc_resolutions.insert(id, item); | ||
281 | } | ||
282 | |||
283 | fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { | ||
284 | self.result.type_of_pat.insert(pat, ty); | ||
285 | } | ||
286 | |||
287 | fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) { | ||
288 | self.result.diagnostics.push(diagnostic); | ||
289 | } | ||
290 | |||
291 | fn make_ty_with_mode( | ||
292 | &mut self, | ||
293 | type_ref: &TypeRef, | ||
294 | impl_trait_mode: ImplTraitLoweringMode, | ||
295 | ) -> Ty { | ||
296 | // FIXME use right resolver for block | ||
297 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) | ||
298 | .with_impl_trait_mode(impl_trait_mode); | ||
299 | let ty = Ty::from_hir(&ctx, type_ref); | ||
300 | let ty = self.insert_type_vars(ty); | ||
301 | self.normalize_associated_types_in(ty) | ||
302 | } | ||
303 | |||
304 | fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { | ||
305 | self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed) | ||
306 | } | ||
307 | |||
308 | /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. | ||
309 | fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { | ||
310 | match ty { | ||
311 | Ty::Unknown => self.table.new_type_var(), | ||
312 | _ => ty, | ||
313 | } | ||
314 | } | ||
315 | |||
316 | fn insert_type_vars(&mut self, ty: Ty) -> Ty { | ||
317 | ty.fold(&mut |ty| self.insert_type_vars_shallow(ty)) | ||
318 | } | ||
319 | |||
320 | fn resolve_obligations_as_possible(&mut self) { | ||
321 | let obligations = mem::replace(&mut self.obligations, Vec::new()); | ||
322 | for obligation in obligations { | ||
323 | let in_env = InEnvironment::new(self.trait_env.clone(), obligation.clone()); | ||
324 | let canonicalized = self.canonicalizer().canonicalize_obligation(in_env); | ||
325 | let solution = | ||
326 | self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone()); | ||
327 | |||
328 | match solution { | ||
329 | Some(Solution::Unique(substs)) => { | ||
330 | canonicalized.apply_solution(self, substs.0); | ||
331 | } | ||
332 | Some(Solution::Ambig(Guidance::Definite(substs))) => { | ||
333 | canonicalized.apply_solution(self, substs.0); | ||
334 | self.obligations.push(obligation); | ||
335 | } | ||
336 | Some(_) => { | ||
337 | // FIXME use this when trying to resolve everything at the end | ||
338 | self.obligations.push(obligation); | ||
339 | } | ||
340 | None => { | ||
341 | // FIXME obligation cannot be fulfilled => diagnostic | ||
342 | } | ||
343 | }; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | ||
348 | self.table.unify(ty1, ty2) | ||
349 | } | ||
350 | |||
351 | /// Resolves the type as far as currently possible, replacing type variables | ||
352 | /// by their known types. All types returned by the infer_* functions should | ||
353 | /// be resolved as far as possible, i.e. contain no type variables with | ||
354 | /// known type. | ||
355 | fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { | ||
356 | self.resolve_obligations_as_possible(); | ||
357 | |||
358 | self.table.resolve_ty_as_possible(ty) | ||
359 | } | ||
360 | |||
361 | fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { | ||
362 | self.table.resolve_ty_shallow(ty) | ||
363 | } | ||
364 | |||
365 | fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty { | ||
366 | self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[]) | ||
367 | } | ||
368 | |||
369 | fn resolve_associated_type_with_params( | ||
370 | &mut self, | ||
371 | inner_ty: Ty, | ||
372 | assoc_ty: Option<TypeAliasId>, | ||
373 | params: &[Ty], | ||
374 | ) -> Ty { | ||
375 | match assoc_ty { | ||
376 | Some(res_assoc_ty) => { | ||
377 | let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container { | ||
378 | hir_def::AssocContainerId::TraitId(trait_) => trait_, | ||
379 | _ => panic!("resolve_associated_type called with non-associated type"), | ||
380 | }; | ||
381 | let ty = self.table.new_type_var(); | ||
382 | let substs = Substs::build_for_def(self.db, res_assoc_ty) | ||
383 | .push(inner_ty) | ||
384 | .fill(params.iter().cloned()) | ||
385 | .build(); | ||
386 | let trait_ref = TraitRef { trait_, substs: substs.clone() }; | ||
387 | let projection = ProjectionPredicate { | ||
388 | ty: ty.clone(), | ||
389 | projection_ty: ProjectionTy { associated_ty: res_assoc_ty, parameters: substs }, | ||
390 | }; | ||
391 | self.obligations.push(Obligation::Trait(trait_ref)); | ||
392 | self.obligations.push(Obligation::Projection(projection)); | ||
393 | self.resolve_ty_as_possible(ty) | ||
394 | } | ||
395 | None => Ty::Unknown, | ||
396 | } | ||
397 | } | ||
398 | |||
399 | /// Recurses through the given type, normalizing associated types mentioned | ||
400 | /// in it by replacing them by type variables and registering obligations to | ||
401 | /// resolve later. This should be done once for every type we get from some | ||
402 | /// type annotation (e.g. from a let type annotation, field type or function | ||
403 | /// call). `make_ty` handles this already, but e.g. for field types we need | ||
404 | /// to do it as well. | ||
405 | fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { | ||
406 | let ty = self.resolve_ty_as_possible(ty); | ||
407 | ty.fold(&mut |ty| match ty { | ||
408 | Ty::Projection(proj_ty) => self.normalize_projection_ty(proj_ty), | ||
409 | _ => ty, | ||
410 | }) | ||
411 | } | ||
412 | |||
413 | fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { | ||
414 | let var = self.table.new_type_var(); | ||
415 | let predicate = ProjectionPredicate { projection_ty: proj_ty, ty: var.clone() }; | ||
416 | let obligation = Obligation::Projection(predicate); | ||
417 | self.obligations.push(obligation); | ||
418 | var | ||
419 | } | ||
420 | |||
421 | fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantId>) { | ||
422 | let path = match path { | ||
423 | Some(path) => path, | ||
424 | None => return (Ty::Unknown, None), | ||
425 | }; | ||
426 | let resolver = &self.resolver; | ||
427 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); | ||
428 | // FIXME: this should resolve assoc items as well, see this example: | ||
429 | // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 | ||
430 | let (resolution, unresolved) = | ||
431 | match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { | ||
432 | Some(it) => it, | ||
433 | None => return (Ty::Unknown, None), | ||
434 | }; | ||
435 | return match resolution { | ||
436 | TypeNs::AdtId(AdtId::StructId(strukt)) => { | ||
437 | let substs = Ty::substs_from_path(&ctx, path, strukt.into(), true); | ||
438 | let ty = self.db.ty(strukt.into()); | ||
439 | let ty = self.insert_type_vars(ty.subst(&substs)); | ||
440 | forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) | ||
441 | } | ||
442 | TypeNs::AdtId(AdtId::UnionId(u)) => { | ||
443 | let substs = Ty::substs_from_path(&ctx, path, u.into(), true); | ||
444 | let ty = self.db.ty(u.into()); | ||
445 | let ty = self.insert_type_vars(ty.subst(&substs)); | ||
446 | forbid_unresolved_segments((ty, Some(u.into())), unresolved) | ||
447 | } | ||
448 | TypeNs::EnumVariantId(var) => { | ||
449 | let substs = Ty::substs_from_path(&ctx, path, var.into(), true); | ||
450 | let ty = self.db.ty(var.parent.into()); | ||
451 | let ty = self.insert_type_vars(ty.subst(&substs)); | ||
452 | forbid_unresolved_segments((ty, Some(var.into())), unresolved) | ||
453 | } | ||
454 | TypeNs::SelfType(impl_id) => { | ||
455 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | ||
456 | let substs = Substs::type_params_for_generics(&generics); | ||
457 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); | ||
458 | match unresolved { | ||
459 | None => { | ||
460 | let variant = ty_variant(&ty); | ||
461 | (ty, variant) | ||
462 | } | ||
463 | Some(1) => { | ||
464 | let segment = path.mod_path().segments.last().unwrap(); | ||
465 | // this could be an enum variant or associated type | ||
466 | if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { | ||
467 | let enum_data = self.db.enum_data(enum_id); | ||
468 | if let Some(local_id) = enum_data.variant(segment) { | ||
469 | let variant = EnumVariantId { parent: enum_id, local_id }; | ||
470 | return (ty, Some(variant.into())); | ||
471 | } | ||
472 | } | ||
473 | // FIXME potentially resolve assoc type | ||
474 | (Ty::Unknown, None) | ||
475 | } | ||
476 | Some(_) => { | ||
477 | // FIXME diagnostic | ||
478 | (Ty::Unknown, None) | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | TypeNs::TypeAliasId(it) => { | ||
483 | let substs = Substs::build_for_def(self.db, it) | ||
484 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) | ||
485 | .build(); | ||
486 | let ty = self.db.ty(it.into()).subst(&substs); | ||
487 | let variant = ty_variant(&ty); | ||
488 | forbid_unresolved_segments((ty, variant), unresolved) | ||
489 | } | ||
490 | TypeNs::AdtSelfType(_) => { | ||
491 | // FIXME this could happen in array size expressions, once we're checking them | ||
492 | (Ty::Unknown, None) | ||
493 | } | ||
494 | TypeNs::GenericParam(_) => { | ||
495 | // FIXME potentially resolve assoc type | ||
496 | (Ty::Unknown, None) | ||
497 | } | ||
498 | TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => { | ||
499 | // FIXME diagnostic | ||
500 | (Ty::Unknown, None) | ||
501 | } | ||
502 | }; | ||
503 | |||
504 | fn forbid_unresolved_segments( | ||
505 | result: (Ty, Option<VariantId>), | ||
506 | unresolved: Option<usize>, | ||
507 | ) -> (Ty, Option<VariantId>) { | ||
508 | if unresolved.is_none() { | ||
509 | result | ||
510 | } else { | ||
511 | // FIXME diagnostic | ||
512 | (Ty::Unknown, None) | ||
513 | } | ||
514 | } | ||
515 | |||
516 | fn ty_variant(ty: &Ty) -> Option<VariantId> { | ||
517 | ty.as_adt().and_then(|(adt_id, _)| match adt_id { | ||
518 | AdtId::StructId(s) => Some(VariantId::StructId(s)), | ||
519 | AdtId::UnionId(u) => Some(VariantId::UnionId(u)), | ||
520 | AdtId::EnumId(_) => { | ||
521 | // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` | ||
522 | None | ||
523 | } | ||
524 | }) | ||
525 | } | ||
526 | } | ||
527 | |||
528 | fn collect_const(&mut self, data: &ConstData) { | ||
529 | self.return_ty = self.make_ty(&data.type_ref); | ||
530 | } | ||
531 | |||
532 | fn collect_static(&mut self, data: &StaticData) { | ||
533 | self.return_ty = self.make_ty(&data.type_ref); | ||
534 | } | ||
535 | |||
536 | fn collect_fn(&mut self, data: &FunctionData) { | ||
537 | let body = Arc::clone(&self.body); // avoid borrow checker problem | ||
538 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) | ||
539 | .with_impl_trait_mode(ImplTraitLoweringMode::Param); | ||
540 | let param_tys = | ||
541 | data.params.iter().map(|type_ref| Ty::from_hir(&ctx, type_ref)).collect::<Vec<_>>(); | ||
542 | for (ty, pat) in param_tys.into_iter().zip(body.params.iter()) { | ||
543 | let ty = self.insert_type_vars(ty); | ||
544 | let ty = self.normalize_associated_types_in(ty); | ||
545 | |||
546 | self.infer_pat(*pat, &ty, BindingMode::default()); | ||
547 | } | ||
548 | let return_ty = self.make_ty_with_mode(&data.ret_type, ImplTraitLoweringMode::Disallowed); // FIXME implement RPIT | ||
549 | self.return_ty = return_ty; | ||
550 | } | ||
551 | |||
552 | fn infer_body(&mut self) { | ||
553 | self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone())); | ||
554 | } | ||
555 | |||
556 | fn resolve_lang_item(&self, name: &str) -> Option<LangItemTarget> { | ||
557 | let krate = self.resolver.krate()?; | ||
558 | let name = SmolStr::new_inline_from_ascii(name.len(), name.as_bytes()); | ||
559 | self.db.lang_item(krate, name) | ||
560 | } | ||
561 | |||
562 | fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { | ||
563 | let path = path![core::iter::IntoIterator]; | ||
564 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; | ||
565 | self.db.trait_data(trait_).associated_type_by_name(&name![Item]) | ||
566 | } | ||
567 | |||
568 | fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { | ||
569 | let path = path![core::ops::Try]; | ||
570 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; | ||
571 | self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) | ||
572 | } | ||
573 | |||
574 | fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> { | ||
575 | let trait_ = self.resolve_lang_item("neg")?.as_trait()?; | ||
576 | self.db.trait_data(trait_).associated_type_by_name(&name![Output]) | ||
577 | } | ||
578 | |||
579 | fn resolve_ops_not_output(&self) -> Option<TypeAliasId> { | ||
580 | let trait_ = self.resolve_lang_item("not")?.as_trait()?; | ||
581 | self.db.trait_data(trait_).associated_type_by_name(&name![Output]) | ||
582 | } | ||
583 | |||
584 | fn resolve_future_future_output(&self) -> Option<TypeAliasId> { | ||
585 | let trait_ = self.resolve_lang_item("future_trait")?.as_trait()?; | ||
586 | self.db.trait_data(trait_).associated_type_by_name(&name![Output]) | ||
587 | } | ||
588 | |||
589 | fn resolve_boxed_box(&self) -> Option<AdtId> { | ||
590 | let struct_ = self.resolve_lang_item("owned_box")?.as_struct()?; | ||
591 | Some(struct_.into()) | ||
592 | } | ||
593 | |||
594 | fn resolve_range_full(&self) -> Option<AdtId> { | ||
595 | let path = path![core::ops::RangeFull]; | ||
596 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | ||
597 | Some(struct_.into()) | ||
598 | } | ||
599 | |||
600 | fn resolve_range(&self) -> Option<AdtId> { | ||
601 | let path = path![core::ops::Range]; | ||
602 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | ||
603 | Some(struct_.into()) | ||
604 | } | ||
605 | |||
606 | fn resolve_range_inclusive(&self) -> Option<AdtId> { | ||
607 | let path = path![core::ops::RangeInclusive]; | ||
608 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | ||
609 | Some(struct_.into()) | ||
610 | } | ||
611 | |||
612 | fn resolve_range_from(&self) -> Option<AdtId> { | ||
613 | let path = path![core::ops::RangeFrom]; | ||
614 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | ||
615 | Some(struct_.into()) | ||
616 | } | ||
617 | |||
618 | fn resolve_range_to(&self) -> Option<AdtId> { | ||
619 | let path = path![core::ops::RangeTo]; | ||
620 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | ||
621 | Some(struct_.into()) | ||
622 | } | ||
623 | |||
624 | fn resolve_range_to_inclusive(&self) -> Option<AdtId> { | ||
625 | let path = path![core::ops::RangeToInclusive]; | ||
626 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | ||
627 | Some(struct_.into()) | ||
628 | } | ||
629 | |||
630 | fn resolve_ops_index(&self) -> Option<TraitId> { | ||
631 | self.resolve_lang_item("index")?.as_trait() | ||
632 | } | ||
633 | |||
634 | fn resolve_ops_index_output(&self) -> Option<TypeAliasId> { | ||
635 | let trait_ = self.resolve_ops_index()?; | ||
636 | self.db.trait_data(trait_).associated_type_by_name(&name![Output]) | ||
637 | } | ||
638 | } | ||
639 | |||
640 | /// The kinds of placeholders we need during type inference. There's separate | ||
641 | /// values for general types, and for integer and float variables. The latter | ||
642 | /// two are used for inference of literal values (e.g. `100` could be one of | ||
643 | /// several integer types). | ||
644 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | ||
645 | pub enum InferTy { | ||
646 | TypeVar(unify::TypeVarId), | ||
647 | IntVar(unify::TypeVarId), | ||
648 | FloatVar(unify::TypeVarId), | ||
649 | MaybeNeverTypeVar(unify::TypeVarId), | ||
650 | } | ||
651 | |||
652 | impl InferTy { | ||
653 | fn to_inner(self) -> unify::TypeVarId { | ||
654 | match self { | ||
655 | InferTy::TypeVar(ty) | ||
656 | | InferTy::IntVar(ty) | ||
657 | | InferTy::FloatVar(ty) | ||
658 | | InferTy::MaybeNeverTypeVar(ty) => ty, | ||
659 | } | ||
660 | } | ||
661 | |||
662 | fn fallback_value(self) -> Ty { | ||
663 | match self { | ||
664 | InferTy::TypeVar(..) => Ty::Unknown, | ||
665 | InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(IntTy::i32())), | ||
666 | InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(FloatTy::f64())), | ||
667 | InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), | ||
668 | } | ||
669 | } | ||
670 | } | ||
671 | |||
672 | /// When inferring an expression, we propagate downward whatever type hint we | ||
673 | /// are able in the form of an `Expectation`. | ||
674 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
675 | struct Expectation { | ||
676 | ty: Ty, | ||
677 | /// See the `rvalue_hint` method. | ||
678 | rvalue_hint: bool, | ||
679 | } | ||
680 | |||
681 | impl Expectation { | ||
682 | /// The expectation that the type of the expression needs to equal the given | ||
683 | /// type. | ||
684 | fn has_type(ty: Ty) -> Self { | ||
685 | Expectation { ty, rvalue_hint: false } | ||
686 | } | ||
687 | |||
688 | /// The following explanation is copied straight from rustc: | ||
689 | /// Provides an expectation for an rvalue expression given an *optional* | ||
690 | /// hint, which is not required for type safety (the resulting type might | ||
691 | /// be checked higher up, as is the case with `&expr` and `box expr`), but | ||
692 | /// is useful in determining the concrete type. | ||
693 | /// | ||
694 | /// The primary use case is where the expected type is a fat pointer, | ||
695 | /// like `&[isize]`. For example, consider the following statement: | ||
696 | /// | ||
697 | /// let x: &[isize] = &[1, 2, 3]; | ||
698 | /// | ||
699 | /// In this case, the expected type for the `&[1, 2, 3]` expression is | ||
700 | /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the | ||
701 | /// expectation `ExpectHasType([isize])`, that would be too strong -- | ||
702 | /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`. | ||
703 | /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced | ||
704 | /// to the type `&[isize]`. Therefore, we propagate this more limited hint, | ||
705 | /// which still is useful, because it informs integer literals and the like. | ||
706 | /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 | ||
707 | /// for examples of where this comes up,. | ||
708 | fn rvalue_hint(ty: Ty) -> Self { | ||
709 | Expectation { ty, rvalue_hint: true } | ||
710 | } | ||
711 | |||
712 | /// This expresses no expectation on the type. | ||
713 | fn none() -> Self { | ||
714 | Expectation { ty: Ty::Unknown, rvalue_hint: false } | ||
715 | } | ||
716 | |||
717 | fn coercion_target(&self) -> &Ty { | ||
718 | if self.rvalue_hint { | ||
719 | &Ty::Unknown | ||
720 | } else { | ||
721 | &self.ty | ||
722 | } | ||
723 | } | ||
724 | } | ||
725 | |||
726 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] | ||
727 | enum Diverges { | ||
728 | Maybe, | ||
729 | Always, | ||
730 | } | ||
731 | |||
732 | impl Diverges { | ||
733 | fn is_always(self) -> bool { | ||
734 | self == Diverges::Always | ||
735 | } | ||
736 | } | ||
737 | |||
738 | impl std::ops::BitAnd for Diverges { | ||
739 | type Output = Self; | ||
740 | fn bitand(self, other: Self) -> Self { | ||
741 | std::cmp::min(self, other) | ||
742 | } | ||
743 | } | ||
744 | |||
745 | impl std::ops::BitOr for Diverges { | ||
746 | type Output = Self; | ||
747 | fn bitor(self, other: Self) -> Self { | ||
748 | std::cmp::max(self, other) | ||
749 | } | ||
750 | } | ||
751 | |||
752 | impl std::ops::BitAndAssign for Diverges { | ||
753 | fn bitand_assign(&mut self, other: Self) { | ||
754 | *self = *self & other; | ||
755 | } | ||
756 | } | ||
757 | |||
758 | impl std::ops::BitOrAssign for Diverges { | ||
759 | fn bitor_assign(&mut self, other: Self) { | ||
760 | *self = *self | other; | ||
761 | } | ||
762 | } | ||
763 | |||
764 | mod diagnostics { | ||
765 | use hir_def::{expr::ExprId, DefWithBodyId}; | ||
766 | use hir_expand::diagnostics::DiagnosticSink; | ||
767 | |||
768 | use crate::{ | ||
769 | db::HirDatabase, | ||
770 | diagnostics::{BreakOutsideOfLoop, NoSuchField}, | ||
771 | }; | ||
772 | |||
773 | #[derive(Debug, PartialEq, Eq, Clone)] | ||
774 | pub(super) enum InferenceDiagnostic { | ||
775 | NoSuchField { expr: ExprId, field: usize }, | ||
776 | BreakOutsideOfLoop { expr: ExprId }, | ||
777 | } | ||
778 | |||
779 | impl InferenceDiagnostic { | ||
780 | pub(super) fn add_to( | ||
781 | &self, | ||
782 | db: &dyn HirDatabase, | ||
783 | owner: DefWithBodyId, | ||
784 | sink: &mut DiagnosticSink, | ||
785 | ) { | ||
786 | match self { | ||
787 | InferenceDiagnostic::NoSuchField { expr, field } => { | ||
788 | let (_, source_map) = db.body_with_source_map(owner); | ||
789 | let field = source_map.field_syntax(*expr, *field); | ||
790 | sink.push(NoSuchField { file: field.file_id, field: field.value }) | ||
791 | } | ||
792 | InferenceDiagnostic::BreakOutsideOfLoop { expr } => { | ||
793 | let (_, source_map) = db.body_with_source_map(owner); | ||
794 | let ptr = source_map | ||
795 | .expr_syntax(*expr) | ||
796 | .expect("break outside of loop in synthetic syntax"); | ||
797 | sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value }) | ||
798 | } | ||
799 | } | ||
800 | } | ||
801 | } | ||
802 | } | ||
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs new file mode 100644 index 000000000..32c7c57cd --- /dev/null +++ b/crates/hir_ty/src/infer/coerce.rs | |||
@@ -0,0 +1,197 @@ | |||
1 | //! Coercion logic. Coercions are certain type conversions that can implicitly | ||
2 | //! happen in certain places, e.g. weakening `&mut` to `&` or deref coercions | ||
3 | //! like going from `&Vec<T>` to `&[T]`. | ||
4 | //! | ||
5 | //! See: https://doc.rust-lang.org/nomicon/coercions.html | ||
6 | |||
7 | use hir_def::{lang_item::LangItemTarget, type_ref::Mutability}; | ||
8 | use test_utils::mark; | ||
9 | |||
10 | use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor}; | ||
11 | |||
12 | use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext}; | ||
13 | |||
14 | impl<'a> InferenceContext<'a> { | ||
15 | /// Unify two types, but may coerce the first one to the second one | ||
16 | /// using "implicit coercion rules" if needed. | ||
17 | pub(super) fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool { | ||
18 | let from_ty = self.resolve_ty_shallow(from_ty).into_owned(); | ||
19 | let to_ty = self.resolve_ty_shallow(to_ty); | ||
20 | self.coerce_inner(from_ty, &to_ty) | ||
21 | } | ||
22 | |||
23 | /// Merge two types from different branches, with possible coercion. | ||
24 | /// | ||
25 | /// Mostly this means trying to coerce one to the other, but | ||
26 | /// - if we have two function types for different functions, we need to | ||
27 | /// coerce both to function pointers; | ||
28 | /// - if we were concerned with lifetime subtyping, we'd need to look for a | ||
29 | /// least upper bound. | ||
30 | pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty { | ||
31 | if self.coerce(ty1, ty2) { | ||
32 | ty2.clone() | ||
33 | } else if self.coerce(ty2, ty1) { | ||
34 | ty1.clone() | ||
35 | } else { | ||
36 | if let (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnDef(_))) = (ty1, ty2) { | ||
37 | mark::hit!(coerce_fn_reification); | ||
38 | // Special case: two function types. Try to coerce both to | ||
39 | // pointers to have a chance at getting a match. See | ||
40 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 | ||
41 | let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig"); | ||
42 | let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig"); | ||
43 | let ptr_ty1 = Ty::fn_ptr(sig1); | ||
44 | let ptr_ty2 = Ty::fn_ptr(sig2); | ||
45 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) | ||
46 | } else { | ||
47 | mark::hit!(coerce_merge_fail_fallback); | ||
48 | ty1.clone() | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | |||
53 | fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { | ||
54 | match (&from_ty, to_ty) { | ||
55 | // Never type will make type variable to fallback to Never Type instead of Unknown. | ||
56 | (ty_app!(TypeCtor::Never), Ty::Infer(InferTy::TypeVar(tv))) => { | ||
57 | let var = self.table.new_maybe_never_type_var(); | ||
58 | self.table.var_unification_table.union_value(*tv, TypeVarValue::Known(var)); | ||
59 | return true; | ||
60 | } | ||
61 | (ty_app!(TypeCtor::Never), _) => return true, | ||
62 | |||
63 | // Trivial cases, this should go after `never` check to | ||
64 | // avoid infer result type to be never | ||
65 | _ => { | ||
66 | if self.table.unify_inner_trivial(&from_ty, &to_ty, 0) { | ||
67 | return true; | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
72 | // Pointer weakening and function to pointer | ||
73 | match (&mut from_ty, to_ty) { | ||
74 | // `*mut T`, `&mut T, `&T`` -> `*const T` | ||
75 | // `&mut T` -> `&T` | ||
76 | // `&mut T` -> `*mut T` | ||
77 | (ty_app!(c1@TypeCtor::RawPtr(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared))) | ||
78 | | (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared))) | ||
79 | | (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::Ref(Mutability::Shared))) | ||
80 | | (ty_app!(c1@TypeCtor::Ref(Mutability::Mut)), ty_app!(c2@TypeCtor::RawPtr(_))) => { | ||
81 | *c1 = *c2; | ||
82 | } | ||
83 | |||
84 | // Illegal mutablity conversion | ||
85 | ( | ||
86 | ty_app!(TypeCtor::RawPtr(Mutability::Shared)), | ||
87 | ty_app!(TypeCtor::RawPtr(Mutability::Mut)), | ||
88 | ) | ||
89 | | ( | ||
90 | ty_app!(TypeCtor::Ref(Mutability::Shared)), | ||
91 | ty_app!(TypeCtor::Ref(Mutability::Mut)), | ||
92 | ) => return false, | ||
93 | |||
94 | // `{function_type}` -> `fn()` | ||
95 | (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnPtr { .. })) => { | ||
96 | match from_ty.callable_sig(self.db) { | ||
97 | None => return false, | ||
98 | Some(sig) => { | ||
99 | from_ty = Ty::fn_ptr(sig); | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | (ty_app!(TypeCtor::Closure { .. }, params), ty_app!(TypeCtor::FnPtr { .. })) => { | ||
105 | from_ty = params[0].clone(); | ||
106 | } | ||
107 | |||
108 | _ => {} | ||
109 | } | ||
110 | |||
111 | if let Some(ret) = self.try_coerce_unsized(&from_ty, &to_ty) { | ||
112 | return ret; | ||
113 | } | ||
114 | |||
115 | // Auto Deref if cannot coerce | ||
116 | match (&from_ty, to_ty) { | ||
117 | // FIXME: DerefMut | ||
118 | (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) => { | ||
119 | self.unify_autoderef_behind_ref(&st1[0], &st2[0]) | ||
120 | } | ||
121 | |||
122 | // Otherwise, normal unify | ||
123 | _ => self.unify(&from_ty, to_ty), | ||
124 | } | ||
125 | } | ||
126 | |||
127 | /// Coerce a type using `from_ty: CoerceUnsized<ty_ty>` | ||
128 | /// | ||
129 | /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html | ||
130 | fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> Option<bool> { | ||
131 | let krate = self.resolver.krate().unwrap(); | ||
132 | let coerce_unsized_trait = match self.db.lang_item(krate, "coerce_unsized".into()) { | ||
133 | Some(LangItemTarget::TraitId(trait_)) => trait_, | ||
134 | _ => return None, | ||
135 | }; | ||
136 | |||
137 | let generic_params = crate::utils::generics(self.db.upcast(), coerce_unsized_trait.into()); | ||
138 | if generic_params.len() != 2 { | ||
139 | // The CoerceUnsized trait should have two generic params: Self and T. | ||
140 | return None; | ||
141 | } | ||
142 | |||
143 | let substs = Substs::build_for_generics(&generic_params) | ||
144 | .push(from_ty.clone()) | ||
145 | .push(to_ty.clone()) | ||
146 | .build(); | ||
147 | let trait_ref = TraitRef { trait_: coerce_unsized_trait, substs }; | ||
148 | let goal = InEnvironment::new(self.trait_env.clone(), Obligation::Trait(trait_ref)); | ||
149 | |||
150 | let canonicalizer = self.canonicalizer(); | ||
151 | let canonicalized = canonicalizer.canonicalize_obligation(goal); | ||
152 | |||
153 | let solution = self.db.trait_solve(krate, canonicalized.value.clone())?; | ||
154 | |||
155 | match solution { | ||
156 | Solution::Unique(v) => { | ||
157 | canonicalized.apply_solution(self, v.0); | ||
158 | } | ||
159 | _ => return None, | ||
160 | }; | ||
161 | |||
162 | Some(true) | ||
163 | } | ||
164 | |||
165 | /// Unify `from_ty` to `to_ty` with optional auto Deref | ||
166 | /// | ||
167 | /// Note that the parameters are already stripped the outer reference. | ||
168 | fn unify_autoderef_behind_ref(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool { | ||
169 | let canonicalized = self.canonicalizer().canonicalize_ty(from_ty.clone()); | ||
170 | let to_ty = self.resolve_ty_shallow(&to_ty); | ||
171 | // FIXME: Auto DerefMut | ||
172 | for derefed_ty in autoderef::autoderef( | ||
173 | self.db, | ||
174 | self.resolver.krate(), | ||
175 | InEnvironment { | ||
176 | value: canonicalized.value.clone(), | ||
177 | environment: self.trait_env.clone(), | ||
178 | }, | ||
179 | ) { | ||
180 | let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value); | ||
181 | match (&*self.resolve_ty_shallow(&derefed_ty), &*to_ty) { | ||
182 | // Stop when constructor matches. | ||
183 | (ty_app!(from_ctor, st1), ty_app!(to_ctor, st2)) if from_ctor == to_ctor => { | ||
184 | // It will not recurse to `coerce`. | ||
185 | return self.table.unify_substs(st1, st2, 0); | ||
186 | } | ||
187 | _ => { | ||
188 | if self.table.unify_inner_trivial(&derefed_ty, &to_ty, 0) { | ||
189 | return true; | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | false | ||
196 | } | ||
197 | } | ||
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs new file mode 100644 index 000000000..a2f849d02 --- /dev/null +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -0,0 +1,873 @@ | |||
1 | //! Type inference for expressions. | ||
2 | |||
3 | use std::iter::{repeat, repeat_with}; | ||
4 | use std::{mem, sync::Arc}; | ||
5 | |||
6 | use hir_def::{ | ||
7 | builtin_type::Signedness, | ||
8 | expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, | ||
9 | path::{GenericArg, GenericArgs}, | ||
10 | resolver::resolver_for_expr, | ||
11 | AdtId, AssocContainerId, FieldId, Lookup, | ||
12 | }; | ||
13 | use hir_expand::name::{name, Name}; | ||
14 | use syntax::ast::RangeOp; | ||
15 | |||
16 | use crate::{ | ||
17 | autoderef, method_resolution, op, | ||
18 | traits::{FnTrait, InEnvironment}, | ||
19 | utils::{generics, variant_data, Generics}, | ||
20 | ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, | ||
21 | TraitRef, Ty, TypeCtor, | ||
22 | }; | ||
23 | |||
24 | use super::{ | ||
25 | find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, | ||
26 | InferenceDiagnostic, TypeMismatch, | ||
27 | }; | ||
28 | |||
29 | impl<'a> InferenceContext<'a> { | ||
30 | pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | ||
31 | let ty = self.infer_expr_inner(tgt_expr, expected); | ||
32 | if ty.is_never() { | ||
33 | // Any expression that produces a value of type `!` must have diverged | ||
34 | self.diverges = Diverges::Always; | ||
35 | } | ||
36 | let could_unify = self.unify(&ty, &expected.ty); | ||
37 | if !could_unify { | ||
38 | self.result.type_mismatches.insert( | ||
39 | tgt_expr, | ||
40 | TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, | ||
41 | ); | ||
42 | } | ||
43 | self.resolve_ty_as_possible(ty) | ||
44 | } | ||
45 | |||
46 | /// Infer type of expression with possibly implicit coerce to the expected type. | ||
47 | /// Return the type after possible coercion. | ||
48 | pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { | ||
49 | let ty = self.infer_expr_inner(expr, &expected); | ||
50 | let ty = if !self.coerce(&ty, &expected.coercion_target()) { | ||
51 | self.result | ||
52 | .type_mismatches | ||
53 | .insert(expr, TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }); | ||
54 | // Return actual type when type mismatch. | ||
55 | // This is needed for diagnostic when return type mismatch. | ||
56 | ty | ||
57 | } else if expected.coercion_target() == &Ty::Unknown { | ||
58 | ty | ||
59 | } else { | ||
60 | expected.ty.clone() | ||
61 | }; | ||
62 | |||
63 | self.resolve_ty_as_possible(ty) | ||
64 | } | ||
65 | |||
66 | fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> { | ||
67 | let krate = self.resolver.krate()?; | ||
68 | let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; | ||
69 | let output_assoc_type = | ||
70 | self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; | ||
71 | let generic_params = generics(self.db.upcast(), fn_once_trait.into()); | ||
72 | if generic_params.len() != 2 { | ||
73 | return None; | ||
74 | } | ||
75 | |||
76 | let mut param_builder = Substs::builder(num_args); | ||
77 | let mut arg_tys = vec![]; | ||
78 | for _ in 0..num_args { | ||
79 | let arg = self.table.new_type_var(); | ||
80 | param_builder = param_builder.push(arg.clone()); | ||
81 | arg_tys.push(arg); | ||
82 | } | ||
83 | let parameters = param_builder.build(); | ||
84 | let arg_ty = Ty::Apply(ApplicationTy { | ||
85 | ctor: TypeCtor::Tuple { cardinality: num_args as u16 }, | ||
86 | parameters, | ||
87 | }); | ||
88 | let substs = | ||
89 | Substs::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build(); | ||
90 | |||
91 | let trait_env = Arc::clone(&self.trait_env); | ||
92 | let implements_fn_trait = | ||
93 | Obligation::Trait(TraitRef { trait_: fn_once_trait, substs: substs.clone() }); | ||
94 | let goal = self.canonicalizer().canonicalize_obligation(InEnvironment { | ||
95 | value: implements_fn_trait.clone(), | ||
96 | environment: trait_env, | ||
97 | }); | ||
98 | if self.db.trait_solve(krate, goal.value).is_some() { | ||
99 | self.obligations.push(implements_fn_trait); | ||
100 | let output_proj_ty = | ||
101 | crate::ProjectionTy { associated_ty: output_assoc_type, parameters: substs }; | ||
102 | let return_ty = self.normalize_projection_ty(output_proj_ty); | ||
103 | Some((arg_tys, return_ty)) | ||
104 | } else { | ||
105 | None | ||
106 | } | ||
107 | } | ||
108 | |||
109 | pub fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> { | ||
110 | match ty.callable_sig(self.db) { | ||
111 | Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())), | ||
112 | None => self.callable_sig_from_fn_trait(ty, num_args), | ||
113 | } | ||
114 | } | ||
115 | |||
116 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | ||
117 | let body = Arc::clone(&self.body); // avoid borrow checker problem | ||
118 | let ty = match &body[tgt_expr] { | ||
119 | Expr::Missing => Ty::Unknown, | ||
120 | Expr::If { condition, then_branch, else_branch } => { | ||
121 | // if let is desugared to match, so this is always simple if | ||
122 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | ||
123 | |||
124 | let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); | ||
125 | let mut both_arms_diverge = Diverges::Always; | ||
126 | |||
127 | let then_ty = self.infer_expr_inner(*then_branch, &expected); | ||
128 | both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); | ||
129 | let else_ty = match else_branch { | ||
130 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), | ||
131 | None => Ty::unit(), | ||
132 | }; | ||
133 | both_arms_diverge &= self.diverges; | ||
134 | |||
135 | self.diverges = condition_diverges | both_arms_diverge; | ||
136 | |||
137 | self.coerce_merge_branch(&then_ty, &else_ty) | ||
138 | } | ||
139 | Expr::Block { statements, tail, .. } => { | ||
140 | // FIXME: Breakable block inference | ||
141 | self.infer_block(statements, *tail, expected) | ||
142 | } | ||
143 | Expr::Unsafe { body } => self.infer_expr(*body, expected), | ||
144 | Expr::TryBlock { body } => { | ||
145 | let _inner = self.infer_expr(*body, expected); | ||
146 | // FIXME should be std::result::Result<{inner}, _> | ||
147 | Ty::Unknown | ||
148 | } | ||
149 | Expr::Loop { body, label } => { | ||
150 | self.breakables.push(BreakableContext { | ||
151 | may_break: false, | ||
152 | break_ty: self.table.new_type_var(), | ||
153 | label: label.clone(), | ||
154 | }); | ||
155 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | ||
156 | |||
157 | let ctxt = self.breakables.pop().expect("breakable stack broken"); | ||
158 | if ctxt.may_break { | ||
159 | self.diverges = Diverges::Maybe; | ||
160 | } | ||
161 | |||
162 | if ctxt.may_break { | ||
163 | ctxt.break_ty | ||
164 | } else { | ||
165 | Ty::simple(TypeCtor::Never) | ||
166 | } | ||
167 | } | ||
168 | Expr::While { condition, body, label } => { | ||
169 | self.breakables.push(BreakableContext { | ||
170 | may_break: false, | ||
171 | break_ty: Ty::Unknown, | ||
172 | label: label.clone(), | ||
173 | }); | ||
174 | // while let is desugared to a match loop, so this is always simple while | ||
175 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | ||
176 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | ||
177 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); | ||
178 | // the body may not run, so it diverging doesn't mean we diverge | ||
179 | self.diverges = Diverges::Maybe; | ||
180 | Ty::unit() | ||
181 | } | ||
182 | Expr::For { iterable, body, pat, label } => { | ||
183 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); | ||
184 | |||
185 | self.breakables.push(BreakableContext { | ||
186 | may_break: false, | ||
187 | break_ty: Ty::Unknown, | ||
188 | label: label.clone(), | ||
189 | }); | ||
190 | let pat_ty = | ||
191 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); | ||
192 | |||
193 | self.infer_pat(*pat, &pat_ty, BindingMode::default()); | ||
194 | |||
195 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | ||
196 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); | ||
197 | // the body may not run, so it diverging doesn't mean we diverge | ||
198 | self.diverges = Diverges::Maybe; | ||
199 | Ty::unit() | ||
200 | } | ||
201 | Expr::Lambda { body, args, ret_type, arg_types } => { | ||
202 | assert_eq!(args.len(), arg_types.len()); | ||
203 | |||
204 | let mut sig_tys = Vec::new(); | ||
205 | |||
206 | // collect explicitly written argument types | ||
207 | for arg_type in arg_types.iter() { | ||
208 | let arg_ty = if let Some(type_ref) = arg_type { | ||
209 | self.make_ty(type_ref) | ||
210 | } else { | ||
211 | self.table.new_type_var() | ||
212 | }; | ||
213 | sig_tys.push(arg_ty); | ||
214 | } | ||
215 | |||
216 | // add return type | ||
217 | let ret_ty = match ret_type { | ||
218 | Some(type_ref) => self.make_ty(type_ref), | ||
219 | None => self.table.new_type_var(), | ||
220 | }; | ||
221 | sig_tys.push(ret_ty.clone()); | ||
222 | let sig_ty = Ty::apply( | ||
223 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1, is_varargs: false }, | ||
224 | Substs(sig_tys.clone().into()), | ||
225 | ); | ||
226 | let closure_ty = | ||
227 | Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty); | ||
228 | |||
229 | // Eagerly try to relate the closure type with the expected | ||
230 | // type, otherwise we often won't have enough information to | ||
231 | // infer the body. | ||
232 | self.coerce(&closure_ty, &expected.ty); | ||
233 | |||
234 | // Now go through the argument patterns | ||
235 | for (arg_pat, arg_ty) in args.iter().zip(sig_tys) { | ||
236 | let resolved = self.resolve_ty_as_possible(arg_ty); | ||
237 | self.infer_pat(*arg_pat, &resolved, BindingMode::default()); | ||
238 | } | ||
239 | |||
240 | let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); | ||
241 | let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); | ||
242 | |||
243 | self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); | ||
244 | |||
245 | self.diverges = prev_diverges; | ||
246 | self.return_ty = prev_ret_ty; | ||
247 | |||
248 | closure_ty | ||
249 | } | ||
250 | Expr::Call { callee, args } => { | ||
251 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); | ||
252 | let canonicalized = self.canonicalizer().canonicalize_ty(callee_ty.clone()); | ||
253 | let mut derefs = autoderef( | ||
254 | self.db, | ||
255 | self.resolver.krate(), | ||
256 | InEnvironment { | ||
257 | value: canonicalized.value.clone(), | ||
258 | environment: self.trait_env.clone(), | ||
259 | }, | ||
260 | ); | ||
261 | let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs | ||
262 | .find_map(|callee_deref_ty| { | ||
263 | self.callable_sig( | ||
264 | &canonicalized.decanonicalize_ty(callee_deref_ty.value), | ||
265 | args.len(), | ||
266 | ) | ||
267 | }) | ||
268 | .unwrap_or((Vec::new(), Ty::Unknown)); | ||
269 | self.register_obligations_for_call(&callee_ty); | ||
270 | self.check_call_arguments(args, ¶m_tys); | ||
271 | self.normalize_associated_types_in(ret_ty) | ||
272 | } | ||
273 | Expr::MethodCall { receiver, args, method_name, generic_args } => self | ||
274 | .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), | ||
275 | Expr::Match { expr, arms } => { | ||
276 | let input_ty = self.infer_expr(*expr, &Expectation::none()); | ||
277 | |||
278 | let mut result_ty = if arms.is_empty() { | ||
279 | Ty::simple(TypeCtor::Never) | ||
280 | } else { | ||
281 | self.table.new_type_var() | ||
282 | }; | ||
283 | |||
284 | let matchee_diverges = self.diverges; | ||
285 | let mut all_arms_diverge = Diverges::Always; | ||
286 | |||
287 | for arm in arms { | ||
288 | self.diverges = Diverges::Maybe; | ||
289 | let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default()); | ||
290 | if let Some(guard_expr) = arm.guard { | ||
291 | self.infer_expr( | ||
292 | guard_expr, | ||
293 | &Expectation::has_type(Ty::simple(TypeCtor::Bool)), | ||
294 | ); | ||
295 | } | ||
296 | |||
297 | let arm_ty = self.infer_expr_inner(arm.expr, &expected); | ||
298 | all_arms_diverge &= self.diverges; | ||
299 | result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); | ||
300 | } | ||
301 | |||
302 | self.diverges = matchee_diverges | all_arms_diverge; | ||
303 | |||
304 | result_ty | ||
305 | } | ||
306 | Expr::Path(p) => { | ||
307 | // FIXME this could be more efficient... | ||
308 | let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); | ||
309 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) | ||
310 | } | ||
311 | Expr::Continue { .. } => Ty::simple(TypeCtor::Never), | ||
312 | Expr::Break { expr, label } => { | ||
313 | let val_ty = if let Some(expr) = expr { | ||
314 | self.infer_expr(*expr, &Expectation::none()) | ||
315 | } else { | ||
316 | Ty::unit() | ||
317 | }; | ||
318 | |||
319 | let last_ty = | ||
320 | if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { | ||
321 | ctxt.break_ty.clone() | ||
322 | } else { | ||
323 | Ty::Unknown | ||
324 | }; | ||
325 | |||
326 | let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); | ||
327 | |||
328 | if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { | ||
329 | ctxt.break_ty = merged_type; | ||
330 | ctxt.may_break = true; | ||
331 | } else { | ||
332 | self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { | ||
333 | expr: tgt_expr, | ||
334 | }); | ||
335 | } | ||
336 | |||
337 | Ty::simple(TypeCtor::Never) | ||
338 | } | ||
339 | Expr::Return { expr } => { | ||
340 | if let Some(expr) = expr { | ||
341 | self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone())); | ||
342 | } else { | ||
343 | let unit = Ty::unit(); | ||
344 | self.coerce(&unit, &self.return_ty.clone()); | ||
345 | } | ||
346 | Ty::simple(TypeCtor::Never) | ||
347 | } | ||
348 | Expr::RecordLit { path, fields, spread } => { | ||
349 | let (ty, def_id) = self.resolve_variant(path.as_ref()); | ||
350 | if let Some(variant) = def_id { | ||
351 | self.write_variant_resolution(tgt_expr.into(), variant); | ||
352 | } | ||
353 | |||
354 | self.unify(&ty, &expected.ty); | ||
355 | |||
356 | let substs = ty.substs().unwrap_or_else(Substs::empty); | ||
357 | let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default(); | ||
358 | let variant_data = def_id.map(|it| variant_data(self.db.upcast(), it)); | ||
359 | for (field_idx, field) in fields.iter().enumerate() { | ||
360 | let field_def = | ||
361 | variant_data.as_ref().and_then(|it| match it.field(&field.name) { | ||
362 | Some(local_id) => Some(FieldId { parent: def_id.unwrap(), local_id }), | ||
363 | None => { | ||
364 | self.push_diagnostic(InferenceDiagnostic::NoSuchField { | ||
365 | expr: tgt_expr, | ||
366 | field: field_idx, | ||
367 | }); | ||
368 | None | ||
369 | } | ||
370 | }); | ||
371 | if let Some(field_def) = field_def { | ||
372 | self.result.record_field_resolutions.insert(field.expr, field_def); | ||
373 | } | ||
374 | let field_ty = field_def | ||
375 | .map_or(Ty::Unknown, |it| field_types[it.local_id].clone().subst(&substs)); | ||
376 | self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); | ||
377 | } | ||
378 | if let Some(expr) = spread { | ||
379 | self.infer_expr(*expr, &Expectation::has_type(ty.clone())); | ||
380 | } | ||
381 | ty | ||
382 | } | ||
383 | Expr::Field { expr, name } => { | ||
384 | let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none()); | ||
385 | let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); | ||
386 | let ty = autoderef::autoderef( | ||
387 | self.db, | ||
388 | self.resolver.krate(), | ||
389 | InEnvironment { | ||
390 | value: canonicalized.value.clone(), | ||
391 | environment: self.trait_env.clone(), | ||
392 | }, | ||
393 | ) | ||
394 | .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) { | ||
395 | Ty::Apply(a_ty) => match a_ty.ctor { | ||
396 | TypeCtor::Tuple { .. } => name | ||
397 | .as_tuple_index() | ||
398 | .and_then(|idx| a_ty.parameters.0.get(idx).cloned()), | ||
399 | TypeCtor::Adt(AdtId::StructId(s)) => { | ||
400 | self.db.struct_data(s).variant_data.field(name).map(|local_id| { | ||
401 | let field = FieldId { parent: s.into(), local_id }; | ||
402 | self.write_field_resolution(tgt_expr, field); | ||
403 | self.db.field_types(s.into())[field.local_id] | ||
404 | .clone() | ||
405 | .subst(&a_ty.parameters) | ||
406 | }) | ||
407 | } | ||
408 | TypeCtor::Adt(AdtId::UnionId(u)) => { | ||
409 | self.db.union_data(u).variant_data.field(name).map(|local_id| { | ||
410 | let field = FieldId { parent: u.into(), local_id }; | ||
411 | self.write_field_resolution(tgt_expr, field); | ||
412 | self.db.field_types(u.into())[field.local_id] | ||
413 | .clone() | ||
414 | .subst(&a_ty.parameters) | ||
415 | }) | ||
416 | } | ||
417 | _ => None, | ||
418 | }, | ||
419 | _ => None, | ||
420 | }) | ||
421 | .unwrap_or(Ty::Unknown); | ||
422 | let ty = self.insert_type_vars(ty); | ||
423 | self.normalize_associated_types_in(ty) | ||
424 | } | ||
425 | Expr::Await { expr } => { | ||
426 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); | ||
427 | self.resolve_associated_type(inner_ty, self.resolve_future_future_output()) | ||
428 | } | ||
429 | Expr::Try { expr } => { | ||
430 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); | ||
431 | self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok()) | ||
432 | } | ||
433 | Expr::Cast { expr, type_ref } => { | ||
434 | let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); | ||
435 | let cast_ty = self.make_ty(type_ref); | ||
436 | // FIXME check the cast... | ||
437 | cast_ty | ||
438 | } | ||
439 | Expr::Ref { expr, rawness, mutability } => { | ||
440 | let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = | ||
441 | &expected.ty.as_reference_or_ptr() | ||
442 | { | ||
443 | if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared { | ||
444 | // FIXME: throw type error - expected mut reference but found shared ref, | ||
445 | // which cannot be coerced | ||
446 | } | ||
447 | if *exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr { | ||
448 | // FIXME: throw type error - expected reference but found ptr, | ||
449 | // which cannot be coerced | ||
450 | } | ||
451 | Expectation::rvalue_hint(Ty::clone(exp_inner)) | ||
452 | } else { | ||
453 | Expectation::none() | ||
454 | }; | ||
455 | let inner_ty = self.infer_expr_inner(*expr, &expectation); | ||
456 | let ty = match rawness { | ||
457 | Rawness::RawPtr => TypeCtor::RawPtr(*mutability), | ||
458 | Rawness::Ref => TypeCtor::Ref(*mutability), | ||
459 | }; | ||
460 | Ty::apply_one(ty, inner_ty) | ||
461 | } | ||
462 | Expr::Box { expr } => { | ||
463 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); | ||
464 | if let Some(box_) = self.resolve_boxed_box() { | ||
465 | Ty::apply_one(TypeCtor::Adt(box_), inner_ty) | ||
466 | } else { | ||
467 | Ty::Unknown | ||
468 | } | ||
469 | } | ||
470 | Expr::UnaryOp { expr, op } => { | ||
471 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); | ||
472 | match op { | ||
473 | UnaryOp::Deref => match self.resolver.krate() { | ||
474 | Some(krate) => { | ||
475 | let canonicalized = self.canonicalizer().canonicalize_ty(inner_ty); | ||
476 | match autoderef::deref( | ||
477 | self.db, | ||
478 | krate, | ||
479 | InEnvironment { | ||
480 | value: &canonicalized.value, | ||
481 | environment: self.trait_env.clone(), | ||
482 | }, | ||
483 | ) { | ||
484 | Some(derefed_ty) => { | ||
485 | canonicalized.decanonicalize_ty(derefed_ty.value) | ||
486 | } | ||
487 | None => Ty::Unknown, | ||
488 | } | ||
489 | } | ||
490 | None => Ty::Unknown, | ||
491 | }, | ||
492 | UnaryOp::Neg => { | ||
493 | match &inner_ty { | ||
494 | // Fast path for builtins | ||
495 | Ty::Apply(ApplicationTy { | ||
496 | ctor: TypeCtor::Int(IntTy { signedness: Signedness::Signed, .. }), | ||
497 | .. | ||
498 | }) | ||
499 | | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. }) | ||
500 | | Ty::Infer(InferTy::IntVar(..)) | ||
501 | | Ty::Infer(InferTy::FloatVar(..)) => inner_ty, | ||
502 | // Otherwise we resolve via the std::ops::Neg trait | ||
503 | _ => self | ||
504 | .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()), | ||
505 | } | ||
506 | } | ||
507 | UnaryOp::Not => { | ||
508 | match &inner_ty { | ||
509 | // Fast path for builtins | ||
510 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. }) | ||
511 | | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(_), .. }) | ||
512 | | Ty::Infer(InferTy::IntVar(..)) => inner_ty, | ||
513 | // Otherwise we resolve via the std::ops::Not trait | ||
514 | _ => self | ||
515 | .resolve_associated_type(inner_ty, self.resolve_ops_not_output()), | ||
516 | } | ||
517 | } | ||
518 | } | ||
519 | } | ||
520 | Expr::BinaryOp { lhs, rhs, op } => match op { | ||
521 | Some(op) => { | ||
522 | let lhs_expectation = match op { | ||
523 | BinaryOp::LogicOp(..) => Expectation::has_type(Ty::simple(TypeCtor::Bool)), | ||
524 | _ => Expectation::none(), | ||
525 | }; | ||
526 | let lhs_ty = self.infer_expr(*lhs, &lhs_expectation); | ||
527 | // FIXME: find implementation of trait corresponding to operation | ||
528 | // symbol and resolve associated `Output` type | ||
529 | let rhs_expectation = op::binary_op_rhs_expectation(*op, lhs_ty.clone()); | ||
530 | let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expectation)); | ||
531 | |||
532 | // FIXME: similar as above, return ty is often associated trait type | ||
533 | op::binary_op_return_ty(*op, lhs_ty, rhs_ty) | ||
534 | } | ||
535 | _ => Ty::Unknown, | ||
536 | }, | ||
537 | Expr::Range { lhs, rhs, range_type } => { | ||
538 | let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none())); | ||
539 | let rhs_expect = lhs_ty | ||
540 | .as_ref() | ||
541 | .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone())); | ||
542 | let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect)); | ||
543 | match (range_type, lhs_ty, rhs_ty) { | ||
544 | (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { | ||
545 | Some(adt) => Ty::simple(TypeCtor::Adt(adt)), | ||
546 | None => Ty::Unknown, | ||
547 | }, | ||
548 | (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { | ||
549 | Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), | ||
550 | None => Ty::Unknown, | ||
551 | }, | ||
552 | (RangeOp::Inclusive, None, Some(ty)) => { | ||
553 | match self.resolve_range_to_inclusive() { | ||
554 | Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), | ||
555 | None => Ty::Unknown, | ||
556 | } | ||
557 | } | ||
558 | (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { | ||
559 | Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), | ||
560 | None => Ty::Unknown, | ||
561 | }, | ||
562 | (RangeOp::Inclusive, Some(_), Some(ty)) => { | ||
563 | match self.resolve_range_inclusive() { | ||
564 | Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), | ||
565 | None => Ty::Unknown, | ||
566 | } | ||
567 | } | ||
568 | (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() { | ||
569 | Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), | ||
570 | None => Ty::Unknown, | ||
571 | }, | ||
572 | (RangeOp::Inclusive, _, None) => Ty::Unknown, | ||
573 | } | ||
574 | } | ||
575 | Expr::Index { base, index } => { | ||
576 | let base_ty = self.infer_expr_inner(*base, &Expectation::none()); | ||
577 | let index_ty = self.infer_expr(*index, &Expectation::none()); | ||
578 | |||
579 | if let (Some(index_trait), Some(krate)) = | ||
580 | (self.resolve_ops_index(), self.resolver.krate()) | ||
581 | { | ||
582 | let canonicalized = self.canonicalizer().canonicalize_ty(base_ty); | ||
583 | let self_ty = method_resolution::resolve_indexing_op( | ||
584 | self.db, | ||
585 | &canonicalized.value, | ||
586 | self.trait_env.clone(), | ||
587 | krate, | ||
588 | index_trait, | ||
589 | ); | ||
590 | let self_ty = | ||
591 | self_ty.map_or(Ty::Unknown, |t| canonicalized.decanonicalize_ty(t.value)); | ||
592 | self.resolve_associated_type_with_params( | ||
593 | self_ty, | ||
594 | self.resolve_ops_index_output(), | ||
595 | &[index_ty], | ||
596 | ) | ||
597 | } else { | ||
598 | Ty::Unknown | ||
599 | } | ||
600 | } | ||
601 | Expr::Tuple { exprs } => { | ||
602 | let mut tys = match &expected.ty { | ||
603 | ty_app!(TypeCtor::Tuple { .. }, st) => st | ||
604 | .iter() | ||
605 | .cloned() | ||
606 | .chain(repeat_with(|| self.table.new_type_var())) | ||
607 | .take(exprs.len()) | ||
608 | .collect::<Vec<_>>(), | ||
609 | _ => (0..exprs.len()).map(|_| self.table.new_type_var()).collect(), | ||
610 | }; | ||
611 | |||
612 | for (expr, ty) in exprs.iter().zip(tys.iter_mut()) { | ||
613 | self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone())); | ||
614 | } | ||
615 | |||
616 | Ty::apply(TypeCtor::Tuple { cardinality: tys.len() as u16 }, Substs(tys.into())) | ||
617 | } | ||
618 | Expr::Array(array) => { | ||
619 | let elem_ty = match &expected.ty { | ||
620 | ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => { | ||
621 | st.as_single().clone() | ||
622 | } | ||
623 | _ => self.table.new_type_var(), | ||
624 | }; | ||
625 | |||
626 | match array { | ||
627 | Array::ElementList(items) => { | ||
628 | for expr in items.iter() { | ||
629 | self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone())); | ||
630 | } | ||
631 | } | ||
632 | Array::Repeat { initializer, repeat } => { | ||
633 | self.infer_expr_coerce( | ||
634 | *initializer, | ||
635 | &Expectation::has_type(elem_ty.clone()), | ||
636 | ); | ||
637 | self.infer_expr( | ||
638 | *repeat, | ||
639 | &Expectation::has_type(Ty::simple(TypeCtor::Int(IntTy::usize()))), | ||
640 | ); | ||
641 | } | ||
642 | } | ||
643 | |||
644 | Ty::apply_one(TypeCtor::Array, elem_ty) | ||
645 | } | ||
646 | Expr::Literal(lit) => match lit { | ||
647 | Literal::Bool(..) => Ty::simple(TypeCtor::Bool), | ||
648 | Literal::String(..) => { | ||
649 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) | ||
650 | } | ||
651 | Literal::ByteString(..) => { | ||
652 | let byte_type = Ty::simple(TypeCtor::Int(IntTy::u8())); | ||
653 | let array_type = Ty::apply_one(TypeCtor::Array, byte_type); | ||
654 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type) | ||
655 | } | ||
656 | Literal::Char(..) => Ty::simple(TypeCtor::Char), | ||
657 | Literal::Int(_v, ty) => match ty { | ||
658 | Some(int_ty) => Ty::simple(TypeCtor::Int((*int_ty).into())), | ||
659 | None => self.table.new_integer_var(), | ||
660 | }, | ||
661 | Literal::Float(_v, ty) => match ty { | ||
662 | Some(float_ty) => Ty::simple(TypeCtor::Float((*float_ty).into())), | ||
663 | None => self.table.new_float_var(), | ||
664 | }, | ||
665 | }, | ||
666 | }; | ||
667 | // use a new type variable if we got Ty::Unknown here | ||
668 | let ty = self.insert_type_vars_shallow(ty); | ||
669 | let ty = self.resolve_ty_as_possible(ty); | ||
670 | self.write_expr_ty(tgt_expr, ty.clone()); | ||
671 | ty | ||
672 | } | ||
673 | |||
674 | fn infer_block( | ||
675 | &mut self, | ||
676 | statements: &[Statement], | ||
677 | tail: Option<ExprId>, | ||
678 | expected: &Expectation, | ||
679 | ) -> Ty { | ||
680 | for stmt in statements { | ||
681 | match stmt { | ||
682 | Statement::Let { pat, type_ref, initializer } => { | ||
683 | let decl_ty = | ||
684 | type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown); | ||
685 | |||
686 | // Always use the declared type when specified | ||
687 | let mut ty = decl_ty.clone(); | ||
688 | |||
689 | if let Some(expr) = initializer { | ||
690 | let actual_ty = | ||
691 | self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone())); | ||
692 | if decl_ty == Ty::Unknown { | ||
693 | ty = actual_ty; | ||
694 | } | ||
695 | } | ||
696 | |||
697 | let ty = self.resolve_ty_as_possible(ty); | ||
698 | self.infer_pat(*pat, &ty, BindingMode::default()); | ||
699 | } | ||
700 | Statement::Expr(expr) => { | ||
701 | self.infer_expr(*expr, &Expectation::none()); | ||
702 | } | ||
703 | } | ||
704 | } | ||
705 | |||
706 | let ty = if let Some(expr) = tail { | ||
707 | self.infer_expr_coerce(expr, expected) | ||
708 | } else { | ||
709 | // Citing rustc: if there is no explicit tail expression, | ||
710 | // that is typically equivalent to a tail expression | ||
711 | // of `()` -- except if the block diverges. In that | ||
712 | // case, there is no value supplied from the tail | ||
713 | // expression (assuming there are no other breaks, | ||
714 | // this implies that the type of the block will be | ||
715 | // `!`). | ||
716 | if self.diverges.is_always() { | ||
717 | // we don't even make an attempt at coercion | ||
718 | self.table.new_maybe_never_type_var() | ||
719 | } else { | ||
720 | self.coerce(&Ty::unit(), expected.coercion_target()); | ||
721 | Ty::unit() | ||
722 | } | ||
723 | }; | ||
724 | ty | ||
725 | } | ||
726 | |||
727 | fn infer_method_call( | ||
728 | &mut self, | ||
729 | tgt_expr: ExprId, | ||
730 | receiver: ExprId, | ||
731 | args: &[ExprId], | ||
732 | method_name: &Name, | ||
733 | generic_args: Option<&GenericArgs>, | ||
734 | ) -> Ty { | ||
735 | let receiver_ty = self.infer_expr(receiver, &Expectation::none()); | ||
736 | let canonicalized_receiver = self.canonicalizer().canonicalize_ty(receiver_ty.clone()); | ||
737 | |||
738 | let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); | ||
739 | |||
740 | let resolved = self.resolver.krate().and_then(|krate| { | ||
741 | method_resolution::lookup_method( | ||
742 | &canonicalized_receiver.value, | ||
743 | self.db, | ||
744 | self.trait_env.clone(), | ||
745 | krate, | ||
746 | &traits_in_scope, | ||
747 | method_name, | ||
748 | ) | ||
749 | }); | ||
750 | let (derefed_receiver_ty, method_ty, def_generics) = match resolved { | ||
751 | Some((ty, func)) => { | ||
752 | let ty = canonicalized_receiver.decanonicalize_ty(ty); | ||
753 | self.write_method_resolution(tgt_expr, func); | ||
754 | (ty, self.db.value_ty(func.into()), Some(generics(self.db.upcast(), func.into()))) | ||
755 | } | ||
756 | None => (receiver_ty, Binders::new(0, Ty::Unknown), None), | ||
757 | }; | ||
758 | let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty); | ||
759 | let method_ty = method_ty.subst(&substs); | ||
760 | let method_ty = self.insert_type_vars(method_ty); | ||
761 | self.register_obligations_for_call(&method_ty); | ||
762 | let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { | ||
763 | Some(sig) => { | ||
764 | if !sig.params().is_empty() { | ||
765 | (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone()) | ||
766 | } else { | ||
767 | (Ty::Unknown, Vec::new(), sig.ret().clone()) | ||
768 | } | ||
769 | } | ||
770 | None => (Ty::Unknown, Vec::new(), Ty::Unknown), | ||
771 | }; | ||
772 | // Apply autoref so the below unification works correctly | ||
773 | // FIXME: return correct autorefs from lookup_method | ||
774 | let actual_receiver_ty = match expected_receiver_ty.as_reference() { | ||
775 | Some((_, mutability)) => Ty::apply_one(TypeCtor::Ref(mutability), derefed_receiver_ty), | ||
776 | _ => derefed_receiver_ty, | ||
777 | }; | ||
778 | self.unify(&expected_receiver_ty, &actual_receiver_ty); | ||
779 | |||
780 | self.check_call_arguments(args, ¶m_tys); | ||
781 | self.normalize_associated_types_in(ret_ty) | ||
782 | } | ||
783 | |||
784 | fn check_call_arguments(&mut self, args: &[ExprId], param_tys: &[Ty]) { | ||
785 | // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 -- | ||
786 | // We do this in a pretty awful way: first we type-check any arguments | ||
787 | // that are not closures, then we type-check the closures. This is so | ||
788 | // that we have more information about the types of arguments when we | ||
789 | // type-check the functions. This isn't really the right way to do this. | ||
790 | for &check_closures in &[false, true] { | ||
791 | let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown)); | ||
792 | for (&arg, param_ty) in args.iter().zip(param_iter) { | ||
793 | let is_closure = matches!(&self.body[arg], Expr::Lambda { .. }); | ||
794 | if is_closure != check_closures { | ||
795 | continue; | ||
796 | } | ||
797 | |||
798 | let param_ty = self.normalize_associated_types_in(param_ty); | ||
799 | self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); | ||
800 | } | ||
801 | } | ||
802 | } | ||
803 | |||
804 | fn substs_for_method_call( | ||
805 | &mut self, | ||
806 | def_generics: Option<Generics>, | ||
807 | generic_args: Option<&GenericArgs>, | ||
808 | receiver_ty: &Ty, | ||
809 | ) -> Substs { | ||
810 | let (parent_params, self_params, type_params, impl_trait_params) = | ||
811 | def_generics.as_ref().map_or((0, 0, 0, 0), |g| g.provenance_split()); | ||
812 | assert_eq!(self_params, 0); // method shouldn't have another Self param | ||
813 | let total_len = parent_params + type_params + impl_trait_params; | ||
814 | let mut substs = Vec::with_capacity(total_len); | ||
815 | // Parent arguments are unknown, except for the receiver type | ||
816 | if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { | ||
817 | for (_id, param) in parent_generics { | ||
818 | if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf { | ||
819 | substs.push(receiver_ty.clone()); | ||
820 | } else { | ||
821 | substs.push(Ty::Unknown); | ||
822 | } | ||
823 | } | ||
824 | } | ||
825 | // handle provided type arguments | ||
826 | if let Some(generic_args) = generic_args { | ||
827 | // if args are provided, it should be all of them, but we can't rely on that | ||
828 | for arg in generic_args.args.iter().take(type_params) { | ||
829 | match arg { | ||
830 | GenericArg::Type(type_ref) => { | ||
831 | let ty = self.make_ty(type_ref); | ||
832 | substs.push(ty); | ||
833 | } | ||
834 | } | ||
835 | } | ||
836 | }; | ||
837 | let supplied_params = substs.len(); | ||
838 | for _ in supplied_params..total_len { | ||
839 | substs.push(Ty::Unknown); | ||
840 | } | ||
841 | assert_eq!(substs.len(), total_len); | ||
842 | Substs(substs.into()) | ||
843 | } | ||
844 | |||
845 | fn register_obligations_for_call(&mut self, callable_ty: &Ty) { | ||
846 | if let Ty::Apply(a_ty) = callable_ty { | ||
847 | if let TypeCtor::FnDef(def) = a_ty.ctor { | ||
848 | let generic_predicates = self.db.generic_predicates(def.into()); | ||
849 | for predicate in generic_predicates.iter() { | ||
850 | let predicate = predicate.clone().subst(&a_ty.parameters); | ||
851 | if let Some(obligation) = Obligation::from_predicate(predicate) { | ||
852 | self.obligations.push(obligation); | ||
853 | } | ||
854 | } | ||
855 | // add obligation for trait implementation, if this is a trait method | ||
856 | match def { | ||
857 | CallableDefId::FunctionId(f) => { | ||
858 | if let AssocContainerId::TraitId(trait_) = | ||
859 | f.lookup(self.db.upcast()).container | ||
860 | { | ||
861 | // construct a TraitDef | ||
862 | let substs = a_ty | ||
863 | .parameters | ||
864 | .prefix(generics(self.db.upcast(), trait_.into()).len()); | ||
865 | self.obligations.push(Obligation::Trait(TraitRef { trait_, substs })); | ||
866 | } | ||
867 | } | ||
868 | CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {} | ||
869 | } | ||
870 | } | ||
871 | } | ||
872 | } | ||
873 | } | ||
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs new file mode 100644 index 000000000..4dd4f9802 --- /dev/null +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -0,0 +1,241 @@ | |||
1 | //! Type inference for patterns. | ||
2 | |||
3 | use std::iter::repeat; | ||
4 | use std::sync::Arc; | ||
5 | |||
6 | use hir_def::{ | ||
7 | expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat}, | ||
8 | path::Path, | ||
9 | type_ref::Mutability, | ||
10 | FieldId, | ||
11 | }; | ||
12 | use hir_expand::name::Name; | ||
13 | use test_utils::mark; | ||
14 | |||
15 | use super::{BindingMode, Expectation, InferenceContext}; | ||
16 | use crate::{utils::variant_data, Substs, Ty, TypeCtor}; | ||
17 | |||
18 | impl<'a> InferenceContext<'a> { | ||
19 | fn infer_tuple_struct_pat( | ||
20 | &mut self, | ||
21 | path: Option<&Path>, | ||
22 | subpats: &[PatId], | ||
23 | expected: &Ty, | ||
24 | default_bm: BindingMode, | ||
25 | id: PatId, | ||
26 | ) -> Ty { | ||
27 | let (ty, def) = self.resolve_variant(path); | ||
28 | let var_data = def.map(|it| variant_data(self.db.upcast(), it)); | ||
29 | if let Some(variant) = def { | ||
30 | self.write_variant_resolution(id.into(), variant); | ||
31 | } | ||
32 | self.unify(&ty, expected); | ||
33 | |||
34 | let substs = ty.substs().unwrap_or_else(Substs::empty); | ||
35 | |||
36 | let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); | ||
37 | |||
38 | for (i, &subpat) in subpats.iter().enumerate() { | ||
39 | let expected_ty = var_data | ||
40 | .as_ref() | ||
41 | .and_then(|d| d.field(&Name::new_tuple_field(i))) | ||
42 | .map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs)); | ||
43 | let expected_ty = self.normalize_associated_types_in(expected_ty); | ||
44 | self.infer_pat(subpat, &expected_ty, default_bm); | ||
45 | } | ||
46 | |||
47 | ty | ||
48 | } | ||
49 | |||
50 | fn infer_record_pat( | ||
51 | &mut self, | ||
52 | path: Option<&Path>, | ||
53 | subpats: &[RecordFieldPat], | ||
54 | expected: &Ty, | ||
55 | default_bm: BindingMode, | ||
56 | id: PatId, | ||
57 | ) -> Ty { | ||
58 | let (ty, def) = self.resolve_variant(path); | ||
59 | let var_data = def.map(|it| variant_data(self.db.upcast(), it)); | ||
60 | if let Some(variant) = def { | ||
61 | self.write_variant_resolution(id.into(), variant); | ||
62 | } | ||
63 | |||
64 | self.unify(&ty, expected); | ||
65 | |||
66 | let substs = ty.substs().unwrap_or_else(Substs::empty); | ||
67 | |||
68 | let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); | ||
69 | for subpat in subpats { | ||
70 | let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name)); | ||
71 | if let Some(local_id) = matching_field { | ||
72 | let field_def = FieldId { parent: def.unwrap(), local_id }; | ||
73 | self.result.record_field_pat_resolutions.insert(subpat.pat, field_def); | ||
74 | } | ||
75 | |||
76 | let expected_ty = | ||
77 | matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs)); | ||
78 | let expected_ty = self.normalize_associated_types_in(expected_ty); | ||
79 | self.infer_pat(subpat.pat, &expected_ty, default_bm); | ||
80 | } | ||
81 | |||
82 | ty | ||
83 | } | ||
84 | |||
85 | pub(super) fn infer_pat( | ||
86 | &mut self, | ||
87 | pat: PatId, | ||
88 | mut expected: &Ty, | ||
89 | mut default_bm: BindingMode, | ||
90 | ) -> Ty { | ||
91 | let body = Arc::clone(&self.body); // avoid borrow checker problem | ||
92 | |||
93 | if is_non_ref_pat(&body, pat) { | ||
94 | while let Some((inner, mutability)) = expected.as_reference() { | ||
95 | expected = inner; | ||
96 | default_bm = match default_bm { | ||
97 | BindingMode::Move => BindingMode::Ref(mutability), | ||
98 | BindingMode::Ref(Mutability::Shared) => BindingMode::Ref(Mutability::Shared), | ||
99 | BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability), | ||
100 | } | ||
101 | } | ||
102 | } else if let Pat::Ref { .. } = &body[pat] { | ||
103 | mark::hit!(match_ergonomics_ref); | ||
104 | // When you encounter a `&pat` pattern, reset to Move. | ||
105 | // This is so that `w` is by value: `let (_, &w) = &(1, &2);` | ||
106 | default_bm = BindingMode::Move; | ||
107 | } | ||
108 | |||
109 | // Lose mutability. | ||
110 | let default_bm = default_bm; | ||
111 | let expected = expected; | ||
112 | |||
113 | let ty = match &body[pat] { | ||
114 | Pat::Tuple { ref args, .. } => { | ||
115 | let expectations = match expected.as_tuple() { | ||
116 | Some(parameters) => &*parameters.0, | ||
117 | _ => &[], | ||
118 | }; | ||
119 | let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown)); | ||
120 | |||
121 | let inner_tys = args | ||
122 | .iter() | ||
123 | .zip(expectations_iter) | ||
124 | .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm)) | ||
125 | .collect(); | ||
126 | |||
127 | Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys)) | ||
128 | } | ||
129 | Pat::Or(ref pats) => { | ||
130 | if let Some((first_pat, rest)) = pats.split_first() { | ||
131 | let ty = self.infer_pat(*first_pat, expected, default_bm); | ||
132 | for pat in rest { | ||
133 | self.infer_pat(*pat, expected, default_bm); | ||
134 | } | ||
135 | ty | ||
136 | } else { | ||
137 | Ty::Unknown | ||
138 | } | ||
139 | } | ||
140 | Pat::Ref { pat, mutability } => { | ||
141 | let expectation = match expected.as_reference() { | ||
142 | Some((inner_ty, exp_mut)) => { | ||
143 | if *mutability != exp_mut { | ||
144 | // FIXME: emit type error? | ||
145 | } | ||
146 | inner_ty | ||
147 | } | ||
148 | _ => &Ty::Unknown, | ||
149 | }; | ||
150 | let subty = self.infer_pat(*pat, expectation, default_bm); | ||
151 | Ty::apply_one(TypeCtor::Ref(*mutability), subty) | ||
152 | } | ||
153 | Pat::TupleStruct { path: p, args: subpats, .. } => { | ||
154 | self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm, pat) | ||
155 | } | ||
156 | Pat::Record { path: p, args: fields, ellipsis: _ } => { | ||
157 | self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) | ||
158 | } | ||
159 | Pat::Path(path) => { | ||
160 | // FIXME use correct resolver for the surrounding expression | ||
161 | let resolver = self.resolver.clone(); | ||
162 | self.infer_path(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) | ||
163 | } | ||
164 | Pat::Bind { mode, name: _, subpat } => { | ||
165 | let mode = if mode == &BindingAnnotation::Unannotated { | ||
166 | default_bm | ||
167 | } else { | ||
168 | BindingMode::convert(*mode) | ||
169 | }; | ||
170 | let inner_ty = if let Some(subpat) = subpat { | ||
171 | self.infer_pat(*subpat, expected, default_bm) | ||
172 | } else { | ||
173 | expected.clone() | ||
174 | }; | ||
175 | let inner_ty = self.insert_type_vars_shallow(inner_ty); | ||
176 | |||
177 | let bound_ty = match mode { | ||
178 | BindingMode::Ref(mutability) => { | ||
179 | Ty::apply_one(TypeCtor::Ref(mutability), inner_ty.clone()) | ||
180 | } | ||
181 | BindingMode::Move => inner_ty.clone(), | ||
182 | }; | ||
183 | let bound_ty = self.resolve_ty_as_possible(bound_ty); | ||
184 | self.write_pat_ty(pat, bound_ty); | ||
185 | return inner_ty; | ||
186 | } | ||
187 | Pat::Slice { prefix, slice, suffix } => { | ||
188 | let (container_ty, elem_ty) = match &expected { | ||
189 | ty_app!(TypeCtor::Array, st) => (TypeCtor::Array, st.as_single().clone()), | ||
190 | ty_app!(TypeCtor::Slice, st) => (TypeCtor::Slice, st.as_single().clone()), | ||
191 | _ => (TypeCtor::Slice, Ty::Unknown), | ||
192 | }; | ||
193 | |||
194 | for pat_id in prefix.iter().chain(suffix) { | ||
195 | self.infer_pat(*pat_id, &elem_ty, default_bm); | ||
196 | } | ||
197 | |||
198 | let pat_ty = Ty::apply_one(container_ty, elem_ty); | ||
199 | if let Some(slice_pat_id) = slice { | ||
200 | self.infer_pat(*slice_pat_id, &pat_ty, default_bm); | ||
201 | } | ||
202 | |||
203 | pat_ty | ||
204 | } | ||
205 | Pat::Wild => expected.clone(), | ||
206 | Pat::Range { start, end } => { | ||
207 | let start_ty = self.infer_expr(*start, &Expectation::has_type(expected.clone())); | ||
208 | let end_ty = self.infer_expr(*end, &Expectation::has_type(start_ty)); | ||
209 | end_ty | ||
210 | } | ||
211 | Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())), | ||
212 | Pat::Missing => Ty::Unknown, | ||
213 | }; | ||
214 | // use a new type variable if we got Ty::Unknown here | ||
215 | let ty = self.insert_type_vars_shallow(ty); | ||
216 | if !self.unify(&ty, expected) { | ||
217 | // FIXME record mismatch, we need to change the type of self.type_mismatches for that | ||
218 | } | ||
219 | let ty = self.resolve_ty_as_possible(ty); | ||
220 | self.write_pat_ty(pat, ty.clone()); | ||
221 | ty | ||
222 | } | ||
223 | } | ||
224 | |||
225 | fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { | ||
226 | match &body[pat] { | ||
227 | Pat::Tuple { .. } | ||
228 | | Pat::TupleStruct { .. } | ||
229 | | Pat::Record { .. } | ||
230 | | Pat::Range { .. } | ||
231 | | Pat::Slice { .. } => true, | ||
232 | Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)), | ||
233 | // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. | ||
234 | Pat::Path(..) => true, | ||
235 | Pat::Lit(expr) => match body[*expr] { | ||
236 | Expr::Literal(Literal::String(..)) => false, | ||
237 | _ => true, | ||
238 | }, | ||
239 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, | ||
240 | } | ||
241 | } | ||
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs new file mode 100644 index 000000000..80d7ed10e --- /dev/null +++ b/crates/hir_ty/src/infer/path.rs | |||
@@ -0,0 +1,287 @@ | |||
1 | //! Path expression resolution. | ||
2 | |||
3 | use std::iter; | ||
4 | |||
5 | use hir_def::{ | ||
6 | path::{Path, PathSegment}, | ||
7 | resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | ||
8 | AdtId, AssocContainerId, AssocItemId, EnumVariantId, Lookup, | ||
9 | }; | ||
10 | use hir_expand::name::Name; | ||
11 | |||
12 | use crate::{method_resolution, Substs, Ty, ValueTyDefId}; | ||
13 | |||
14 | use super::{ExprOrPatId, InferenceContext, TraitRef}; | ||
15 | |||
16 | impl<'a> InferenceContext<'a> { | ||
17 | pub(super) fn infer_path( | ||
18 | &mut self, | ||
19 | resolver: &Resolver, | ||
20 | path: &Path, | ||
21 | id: ExprOrPatId, | ||
22 | ) -> Option<Ty> { | ||
23 | let ty = self.resolve_value_path(resolver, path, id)?; | ||
24 | let ty = self.insert_type_vars(ty); | ||
25 | let ty = self.normalize_associated_types_in(ty); | ||
26 | Some(ty) | ||
27 | } | ||
28 | |||
29 | fn resolve_value_path( | ||
30 | &mut self, | ||
31 | resolver: &Resolver, | ||
32 | path: &Path, | ||
33 | id: ExprOrPatId, | ||
34 | ) -> Option<Ty> { | ||
35 | let (value, self_subst) = if let Some(type_ref) = path.type_anchor() { | ||
36 | if path.segments().is_empty() { | ||
37 | // This can't actually happen syntax-wise | ||
38 | return None; | ||
39 | } | ||
40 | let ty = self.make_ty(type_ref); | ||
41 | let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); | ||
42 | let ctx = crate::lower::TyLoweringContext::new(self.db, &resolver); | ||
43 | let (ty, _) = Ty::from_type_relative_path(&ctx, ty, None, remaining_segments_for_ty); | ||
44 | self.resolve_ty_assoc_item( | ||
45 | ty, | ||
46 | &path.segments().last().expect("path had at least one segment").name, | ||
47 | id, | ||
48 | )? | ||
49 | } else { | ||
50 | let value_or_partial = | ||
51 | resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path())?; | ||
52 | |||
53 | match value_or_partial { | ||
54 | ResolveValueResult::ValueNs(it) => (it, None), | ||
55 | ResolveValueResult::Partial(def, remaining_index) => { | ||
56 | self.resolve_assoc_item(def, path, remaining_index, id)? | ||
57 | } | ||
58 | } | ||
59 | }; | ||
60 | |||
61 | let typable: ValueTyDefId = match value { | ||
62 | ValueNs::LocalBinding(pat) => { | ||
63 | let ty = self.result.type_of_pat.get(pat)?.clone(); | ||
64 | let ty = self.resolve_ty_as_possible(ty); | ||
65 | return Some(ty); | ||
66 | } | ||
67 | ValueNs::FunctionId(it) => it.into(), | ||
68 | ValueNs::ConstId(it) => it.into(), | ||
69 | ValueNs::StaticId(it) => it.into(), | ||
70 | ValueNs::StructId(it) => { | ||
71 | self.write_variant_resolution(id, it.into()); | ||
72 | |||
73 | it.into() | ||
74 | } | ||
75 | ValueNs::EnumVariantId(it) => { | ||
76 | self.write_variant_resolution(id, it.into()); | ||
77 | |||
78 | it.into() | ||
79 | } | ||
80 | ValueNs::ImplSelf(impl_id) => { | ||
81 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | ||
82 | let substs = Substs::type_params_for_generics(&generics); | ||
83 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); | ||
84 | if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { | ||
85 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); | ||
86 | return Some(ty); | ||
87 | } else { | ||
88 | // FIXME: diagnostic, invalid Self reference | ||
89 | return None; | ||
90 | } | ||
91 | } | ||
92 | }; | ||
93 | |||
94 | let ty = self.db.value_ty(typable); | ||
95 | // self_subst is just for the parent | ||
96 | let parent_substs = self_subst.unwrap_or_else(Substs::empty); | ||
97 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); | ||
98 | let substs = Ty::substs_from_path(&ctx, path, typable, true); | ||
99 | let full_substs = Substs::builder(substs.len()) | ||
100 | .use_parent_substs(&parent_substs) | ||
101 | .fill(substs.0[parent_substs.len()..].iter().cloned()) | ||
102 | .build(); | ||
103 | let ty = ty.subst(&full_substs); | ||
104 | Some(ty) | ||
105 | } | ||
106 | |||
107 | fn resolve_assoc_item( | ||
108 | &mut self, | ||
109 | def: TypeNs, | ||
110 | path: &Path, | ||
111 | remaining_index: usize, | ||
112 | id: ExprOrPatId, | ||
113 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
114 | assert!(remaining_index < path.segments().len()); | ||
115 | // there may be more intermediate segments between the resolved one and | ||
116 | // the end. Only the last segment needs to be resolved to a value; from | ||
117 | // the segments before that, we need to get either a type or a trait ref. | ||
118 | |||
119 | let resolved_segment = path.segments().get(remaining_index - 1).unwrap(); | ||
120 | let remaining_segments = path.segments().skip(remaining_index); | ||
121 | let is_before_last = remaining_segments.len() == 1; | ||
122 | |||
123 | match (def, is_before_last) { | ||
124 | (TypeNs::TraitId(trait_), true) => { | ||
125 | let segment = | ||
126 | remaining_segments.last().expect("there should be at least one segment here"); | ||
127 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); | ||
128 | let trait_ref = TraitRef::from_resolved_path(&ctx, trait_, resolved_segment, None); | ||
129 | self.resolve_trait_assoc_item(trait_ref, segment, id) | ||
130 | } | ||
131 | (def, _) => { | ||
132 | // Either we already have a type (e.g. `Vec::new`), or we have a | ||
133 | // trait but it's not the last segment, so the next segment | ||
134 | // should resolve to an associated type of that trait (e.g. `<T | ||
135 | // as Iterator>::Item::default`) | ||
136 | let remaining_segments_for_ty = | ||
137 | remaining_segments.take(remaining_segments.len() - 1); | ||
138 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); | ||
139 | let (ty, _) = Ty::from_partly_resolved_hir_path( | ||
140 | &ctx, | ||
141 | def, | ||
142 | resolved_segment, | ||
143 | remaining_segments_for_ty, | ||
144 | true, | ||
145 | ); | ||
146 | if let Ty::Unknown = ty { | ||
147 | return None; | ||
148 | } | ||
149 | |||
150 | let ty = self.insert_type_vars(ty); | ||
151 | let ty = self.normalize_associated_types_in(ty); | ||
152 | |||
153 | let segment = | ||
154 | remaining_segments.last().expect("there should be at least one segment here"); | ||
155 | |||
156 | self.resolve_ty_assoc_item(ty, &segment.name, id) | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | fn resolve_trait_assoc_item( | ||
162 | &mut self, | ||
163 | trait_ref: TraitRef, | ||
164 | segment: PathSegment<'_>, | ||
165 | id: ExprOrPatId, | ||
166 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
167 | let trait_ = trait_ref.trait_; | ||
168 | let item = | ||
169 | self.db.trait_data(trait_).items.iter().map(|(_name, id)| (*id)).find_map(|item| { | ||
170 | match item { | ||
171 | AssocItemId::FunctionId(func) => { | ||
172 | if segment.name == &self.db.function_data(func).name { | ||
173 | Some(AssocItemId::FunctionId(func)) | ||
174 | } else { | ||
175 | None | ||
176 | } | ||
177 | } | ||
178 | |||
179 | AssocItemId::ConstId(konst) => { | ||
180 | if self | ||
181 | .db | ||
182 | .const_data(konst) | ||
183 | .name | ||
184 | .as_ref() | ||
185 | .map_or(false, |n| n == segment.name) | ||
186 | { | ||
187 | Some(AssocItemId::ConstId(konst)) | ||
188 | } else { | ||
189 | None | ||
190 | } | ||
191 | } | ||
192 | AssocItemId::TypeAliasId(_) => None, | ||
193 | } | ||
194 | })?; | ||
195 | let def = match item { | ||
196 | AssocItemId::FunctionId(f) => ValueNs::FunctionId(f), | ||
197 | AssocItemId::ConstId(c) => ValueNs::ConstId(c), | ||
198 | AssocItemId::TypeAliasId(_) => unreachable!(), | ||
199 | }; | ||
200 | |||
201 | self.write_assoc_resolution(id, item); | ||
202 | Some((def, Some(trait_ref.substs))) | ||
203 | } | ||
204 | |||
205 | fn resolve_ty_assoc_item( | ||
206 | &mut self, | ||
207 | ty: Ty, | ||
208 | name: &Name, | ||
209 | id: ExprOrPatId, | ||
210 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
211 | if let Ty::Unknown = ty { | ||
212 | return None; | ||
213 | } | ||
214 | |||
215 | if let Some(result) = self.resolve_enum_variant_on_ty(&ty, name, id) { | ||
216 | return Some(result); | ||
217 | } | ||
218 | |||
219 | let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); | ||
220 | let krate = self.resolver.krate()?; | ||
221 | let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); | ||
222 | |||
223 | method_resolution::iterate_method_candidates( | ||
224 | &canonical_ty.value, | ||
225 | self.db, | ||
226 | self.trait_env.clone(), | ||
227 | krate, | ||
228 | &traits_in_scope, | ||
229 | Some(name), | ||
230 | method_resolution::LookupMode::Path, | ||
231 | move |_ty, item| { | ||
232 | let (def, container) = match item { | ||
233 | AssocItemId::FunctionId(f) => { | ||
234 | (ValueNs::FunctionId(f), f.lookup(self.db.upcast()).container) | ||
235 | } | ||
236 | AssocItemId::ConstId(c) => { | ||
237 | (ValueNs::ConstId(c), c.lookup(self.db.upcast()).container) | ||
238 | } | ||
239 | AssocItemId::TypeAliasId(_) => unreachable!(), | ||
240 | }; | ||
241 | let substs = match container { | ||
242 | AssocContainerId::ImplId(impl_id) => { | ||
243 | let impl_substs = Substs::build_for_def(self.db, impl_id) | ||
244 | .fill(iter::repeat_with(|| self.table.new_type_var())) | ||
245 | .build(); | ||
246 | let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs); | ||
247 | self.unify(&impl_self_ty, &ty); | ||
248 | Some(impl_substs) | ||
249 | } | ||
250 | AssocContainerId::TraitId(trait_) => { | ||
251 | // we're picking this method | ||
252 | let trait_substs = Substs::build_for_def(self.db, trait_) | ||
253 | .push(ty.clone()) | ||
254 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) | ||
255 | .build(); | ||
256 | self.obligations.push(super::Obligation::Trait(TraitRef { | ||
257 | trait_, | ||
258 | substs: trait_substs.clone(), | ||
259 | })); | ||
260 | Some(trait_substs) | ||
261 | } | ||
262 | AssocContainerId::ContainerId(_) => None, | ||
263 | }; | ||
264 | |||
265 | self.write_assoc_resolution(id, item); | ||
266 | Some((def, substs)) | ||
267 | }, | ||
268 | ) | ||
269 | } | ||
270 | |||
271 | fn resolve_enum_variant_on_ty( | ||
272 | &mut self, | ||
273 | ty: &Ty, | ||
274 | name: &Name, | ||
275 | id: ExprOrPatId, | ||
276 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
277 | let (enum_id, subst) = match ty.as_adt() { | ||
278 | Some((AdtId::EnumId(e), subst)) => (e, subst), | ||
279 | _ => return None, | ||
280 | }; | ||
281 | let enum_data = self.db.enum_data(enum_id); | ||
282 | let local_id = enum_data.variant(name)?; | ||
283 | let variant = EnumVariantId { parent: enum_id, local_id }; | ||
284 | self.write_variant_resolution(id, variant.into()); | ||
285 | Some((ValueNs::EnumVariantId(variant), Some(subst.clone()))) | ||
286 | } | ||
287 | } | ||
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs new file mode 100644 index 000000000..2e895d911 --- /dev/null +++ b/crates/hir_ty/src/infer/unify.rs | |||
@@ -0,0 +1,474 @@ | |||
1 | //! Unification and canonicalization logic. | ||
2 | |||
3 | use std::borrow::Cow; | ||
4 | |||
5 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; | ||
6 | |||
7 | use test_utils::mark; | ||
8 | |||
9 | use super::{InferenceContext, Obligation}; | ||
10 | use crate::{ | ||
11 | BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, | ||
12 | TyKind, TypeCtor, TypeWalk, | ||
13 | }; | ||
14 | |||
15 | impl<'a> InferenceContext<'a> { | ||
16 | pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b> | ||
17 | where | ||
18 | 'a: 'b, | ||
19 | { | ||
20 | Canonicalizer { ctx: self, free_vars: Vec::new(), var_stack: Vec::new() } | ||
21 | } | ||
22 | } | ||
23 | |||
24 | pub(super) struct Canonicalizer<'a, 'b> | ||
25 | where | ||
26 | 'a: 'b, | ||
27 | { | ||
28 | ctx: &'b mut InferenceContext<'a>, | ||
29 | free_vars: Vec<InferTy>, | ||
30 | /// A stack of type variables that is used to detect recursive types (which | ||
31 | /// are an error, but we need to protect against them to avoid stack | ||
32 | /// overflows). | ||
33 | var_stack: Vec<TypeVarId>, | ||
34 | } | ||
35 | |||
36 | #[derive(Debug)] | ||
37 | pub(super) struct Canonicalized<T> { | ||
38 | pub value: Canonical<T>, | ||
39 | free_vars: Vec<InferTy>, | ||
40 | } | ||
41 | |||
42 | impl<'a, 'b> Canonicalizer<'a, 'b> | ||
43 | where | ||
44 | 'a: 'b, | ||
45 | { | ||
46 | fn add(&mut self, free_var: InferTy) -> usize { | ||
47 | self.free_vars.iter().position(|&v| v == free_var).unwrap_or_else(|| { | ||
48 | let next_index = self.free_vars.len(); | ||
49 | self.free_vars.push(free_var); | ||
50 | next_index | ||
51 | }) | ||
52 | } | ||
53 | |||
54 | fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: DebruijnIndex) -> T { | ||
55 | t.fold_binders( | ||
56 | &mut |ty, binders| match ty { | ||
57 | Ty::Infer(tv) => { | ||
58 | let inner = tv.to_inner(); | ||
59 | if self.var_stack.contains(&inner) { | ||
60 | // recursive type | ||
61 | return tv.fallback_value(); | ||
62 | } | ||
63 | if let Some(known_ty) = | ||
64 | self.ctx.table.var_unification_table.inlined_probe_value(inner).known() | ||
65 | { | ||
66 | self.var_stack.push(inner); | ||
67 | let result = self.do_canonicalize(known_ty.clone(), binders); | ||
68 | self.var_stack.pop(); | ||
69 | result | ||
70 | } else { | ||
71 | let root = self.ctx.table.var_unification_table.find(inner); | ||
72 | let free_var = match tv { | ||
73 | InferTy::TypeVar(_) => InferTy::TypeVar(root), | ||
74 | InferTy::IntVar(_) => InferTy::IntVar(root), | ||
75 | InferTy::FloatVar(_) => InferTy::FloatVar(root), | ||
76 | InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root), | ||
77 | }; | ||
78 | let position = self.add(free_var); | ||
79 | Ty::Bound(BoundVar::new(binders, position)) | ||
80 | } | ||
81 | } | ||
82 | _ => ty, | ||
83 | }, | ||
84 | binders, | ||
85 | ) | ||
86 | } | ||
87 | |||
88 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { | ||
89 | let kinds = self | ||
90 | .free_vars | ||
91 | .iter() | ||
92 | .map(|v| match v { | ||
93 | // mapping MaybeNeverTypeVar to the same kind as general ones | ||
94 | // should be fine, because as opposed to int or float type vars, | ||
95 | // they don't restrict what kind of type can go into them, they | ||
96 | // just affect fallback. | ||
97 | InferTy::TypeVar(_) | InferTy::MaybeNeverTypeVar(_) => TyKind::General, | ||
98 | InferTy::IntVar(_) => TyKind::Integer, | ||
99 | InferTy::FloatVar(_) => TyKind::Float, | ||
100 | }) | ||
101 | .collect(); | ||
102 | Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars } | ||
103 | } | ||
104 | |||
105 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { | ||
106 | let result = self.do_canonicalize(ty, DebruijnIndex::INNERMOST); | ||
107 | self.into_canonicalized(result) | ||
108 | } | ||
109 | |||
110 | pub(crate) fn canonicalize_obligation( | ||
111 | mut self, | ||
112 | obligation: InEnvironment<Obligation>, | ||
113 | ) -> Canonicalized<InEnvironment<Obligation>> { | ||
114 | let result = match obligation.value { | ||
115 | Obligation::Trait(tr) => { | ||
116 | Obligation::Trait(self.do_canonicalize(tr, DebruijnIndex::INNERMOST)) | ||
117 | } | ||
118 | Obligation::Projection(pr) => { | ||
119 | Obligation::Projection(self.do_canonicalize(pr, DebruijnIndex::INNERMOST)) | ||
120 | } | ||
121 | }; | ||
122 | self.into_canonicalized(InEnvironment { | ||
123 | value: result, | ||
124 | environment: obligation.environment, | ||
125 | }) | ||
126 | } | ||
127 | } | ||
128 | |||
129 | impl<T> Canonicalized<T> { | ||
130 | pub fn decanonicalize_ty(&self, mut ty: Ty) -> Ty { | ||
131 | ty.walk_mut_binders( | ||
132 | &mut |ty, binders| { | ||
133 | if let &mut Ty::Bound(bound) = ty { | ||
134 | if bound.debruijn >= binders { | ||
135 | *ty = Ty::Infer(self.free_vars[bound.index]); | ||
136 | } | ||
137 | } | ||
138 | }, | ||
139 | DebruijnIndex::INNERMOST, | ||
140 | ); | ||
141 | ty | ||
142 | } | ||
143 | |||
144 | pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Substs>) { | ||
145 | // the solution may contain new variables, which we need to convert to new inference vars | ||
146 | let new_vars = Substs( | ||
147 | solution | ||
148 | .kinds | ||
149 | .iter() | ||
150 | .map(|k| match k { | ||
151 | TyKind::General => ctx.table.new_type_var(), | ||
152 | TyKind::Integer => ctx.table.new_integer_var(), | ||
153 | TyKind::Float => ctx.table.new_float_var(), | ||
154 | }) | ||
155 | .collect(), | ||
156 | ); | ||
157 | for (i, ty) in solution.value.into_iter().enumerate() { | ||
158 | let var = self.free_vars[i]; | ||
159 | // eagerly replace projections in the type; we may be getting types | ||
160 | // e.g. from where clauses where this hasn't happened yet | ||
161 | let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars)); | ||
162 | ctx.table.unify(&Ty::Infer(var), &ty); | ||
163 | } | ||
164 | } | ||
165 | } | ||
166 | |||
167 | pub fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substs> { | ||
168 | let mut table = InferenceTable::new(); | ||
169 | let vars = Substs( | ||
170 | tys.kinds | ||
171 | .iter() | ||
172 | // we always use type vars here because we want everything to | ||
173 | // fallback to Unknown in the end (kind of hacky, as below) | ||
174 | .map(|_| table.new_type_var()) | ||
175 | .collect(), | ||
176 | ); | ||
177 | let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars); | ||
178 | let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars); | ||
179 | if !table.unify(&ty1_with_vars, &ty2_with_vars) { | ||
180 | return None; | ||
181 | } | ||
182 | // default any type vars that weren't unified back to their original bound vars | ||
183 | // (kind of hacky) | ||
184 | for (i, var) in vars.iter().enumerate() { | ||
185 | if &*table.resolve_ty_shallow(var) == var { | ||
186 | table.unify(var, &Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i))); | ||
187 | } | ||
188 | } | ||
189 | Some( | ||
190 | Substs::builder(tys.kinds.len()) | ||
191 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) | ||
192 | .build(), | ||
193 | ) | ||
194 | } | ||
195 | |||
196 | #[derive(Clone, Debug)] | ||
197 | pub(crate) struct InferenceTable { | ||
198 | pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>, | ||
199 | } | ||
200 | |||
201 | impl InferenceTable { | ||
202 | pub fn new() -> Self { | ||
203 | InferenceTable { var_unification_table: InPlaceUnificationTable::new() } | ||
204 | } | ||
205 | |||
206 | pub fn new_type_var(&mut self) -> Ty { | ||
207 | Ty::Infer(InferTy::TypeVar(self.var_unification_table.new_key(TypeVarValue::Unknown))) | ||
208 | } | ||
209 | |||
210 | pub fn new_integer_var(&mut self) -> Ty { | ||
211 | Ty::Infer(InferTy::IntVar(self.var_unification_table.new_key(TypeVarValue::Unknown))) | ||
212 | } | ||
213 | |||
214 | pub fn new_float_var(&mut self) -> Ty { | ||
215 | Ty::Infer(InferTy::FloatVar(self.var_unification_table.new_key(TypeVarValue::Unknown))) | ||
216 | } | ||
217 | |||
218 | pub fn new_maybe_never_type_var(&mut self) -> Ty { | ||
219 | Ty::Infer(InferTy::MaybeNeverTypeVar( | ||
220 | self.var_unification_table.new_key(TypeVarValue::Unknown), | ||
221 | )) | ||
222 | } | ||
223 | |||
224 | pub fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { | ||
225 | self.resolve_ty_completely_inner(&mut Vec::new(), ty) | ||
226 | } | ||
227 | |||
228 | pub fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { | ||
229 | self.resolve_ty_as_possible_inner(&mut Vec::new(), ty) | ||
230 | } | ||
231 | |||
232 | pub fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | ||
233 | self.unify_inner(ty1, ty2, 0) | ||
234 | } | ||
235 | |||
236 | pub fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool { | ||
237 | substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth)) | ||
238 | } | ||
239 | |||
240 | fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { | ||
241 | if depth > 1000 { | ||
242 | // prevent stackoverflows | ||
243 | panic!("infinite recursion in unification"); | ||
244 | } | ||
245 | if ty1 == ty2 { | ||
246 | return true; | ||
247 | } | ||
248 | // try to resolve type vars first | ||
249 | let ty1 = self.resolve_ty_shallow(ty1); | ||
250 | let ty2 = self.resolve_ty_shallow(ty2); | ||
251 | match (&*ty1, &*ty2) { | ||
252 | (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { | ||
253 | self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) | ||
254 | } | ||
255 | |||
256 | _ => self.unify_inner_trivial(&ty1, &ty2, depth), | ||
257 | } | ||
258 | } | ||
259 | |||
260 | pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { | ||
261 | match (ty1, ty2) { | ||
262 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, | ||
263 | |||
264 | (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true, | ||
265 | |||
266 | (Ty::Dyn(dyn1), Ty::Dyn(dyn2)) if dyn1.len() == dyn2.len() => { | ||
267 | for (pred1, pred2) in dyn1.iter().zip(dyn2.iter()) { | ||
268 | if !self.unify_preds(pred1, pred2, depth + 1) { | ||
269 | return false; | ||
270 | } | ||
271 | } | ||
272 | true | ||
273 | } | ||
274 | |||
275 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) | ||
276 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) | ||
277 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) | ||
278 | | ( | ||
279 | Ty::Infer(InferTy::MaybeNeverTypeVar(tv1)), | ||
280 | Ty::Infer(InferTy::MaybeNeverTypeVar(tv2)), | ||
281 | ) => { | ||
282 | // both type vars are unknown since we tried to resolve them | ||
283 | self.var_unification_table.union(*tv1, *tv2); | ||
284 | true | ||
285 | } | ||
286 | |||
287 | // The order of MaybeNeverTypeVar matters here. | ||
288 | // Unifying MaybeNeverTypeVar and TypeVar will let the latter become MaybeNeverTypeVar. | ||
289 | // Unifying MaybeNeverTypeVar and other concrete type will let the former become it. | ||
290 | (Ty::Infer(InferTy::TypeVar(tv)), other) | ||
291 | | (other, Ty::Infer(InferTy::TypeVar(tv))) | ||
292 | | (Ty::Infer(InferTy::MaybeNeverTypeVar(tv)), other) | ||
293 | | (other, Ty::Infer(InferTy::MaybeNeverTypeVar(tv))) | ||
294 | | (Ty::Infer(InferTy::IntVar(tv)), other @ ty_app!(TypeCtor::Int(_))) | ||
295 | | (other @ ty_app!(TypeCtor::Int(_)), Ty::Infer(InferTy::IntVar(tv))) | ||
296 | | (Ty::Infer(InferTy::FloatVar(tv)), other @ ty_app!(TypeCtor::Float(_))) | ||
297 | | (other @ ty_app!(TypeCtor::Float(_)), Ty::Infer(InferTy::FloatVar(tv))) => { | ||
298 | // the type var is unknown since we tried to resolve it | ||
299 | self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone())); | ||
300 | true | ||
301 | } | ||
302 | |||
303 | _ => false, | ||
304 | } | ||
305 | } | ||
306 | |||
307 | fn unify_preds( | ||
308 | &mut self, | ||
309 | pred1: &GenericPredicate, | ||
310 | pred2: &GenericPredicate, | ||
311 | depth: usize, | ||
312 | ) -> bool { | ||
313 | match (pred1, pred2) { | ||
314 | (GenericPredicate::Implemented(tr1), GenericPredicate::Implemented(tr2)) | ||
315 | if tr1.trait_ == tr2.trait_ => | ||
316 | { | ||
317 | self.unify_substs(&tr1.substs, &tr2.substs, depth + 1) | ||
318 | } | ||
319 | (GenericPredicate::Projection(proj1), GenericPredicate::Projection(proj2)) | ||
320 | if proj1.projection_ty.associated_ty == proj2.projection_ty.associated_ty => | ||
321 | { | ||
322 | self.unify_substs( | ||
323 | &proj1.projection_ty.parameters, | ||
324 | &proj2.projection_ty.parameters, | ||
325 | depth + 1, | ||
326 | ) && self.unify_inner(&proj1.ty, &proj2.ty, depth + 1) | ||
327 | } | ||
328 | _ => false, | ||
329 | } | ||
330 | } | ||
331 | |||
332 | /// If `ty` is a type variable with known type, returns that type; | ||
333 | /// otherwise, return ty. | ||
334 | pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { | ||
335 | let mut ty = Cow::Borrowed(ty); | ||
336 | // The type variable could resolve to a int/float variable. Hence try | ||
337 | // resolving up to three times; each type of variable shouldn't occur | ||
338 | // more than once | ||
339 | for i in 0..3 { | ||
340 | if i > 0 { | ||
341 | mark::hit!(type_var_resolves_to_int_var); | ||
342 | } | ||
343 | match &*ty { | ||
344 | Ty::Infer(tv) => { | ||
345 | let inner = tv.to_inner(); | ||
346 | match self.var_unification_table.inlined_probe_value(inner).known() { | ||
347 | Some(known_ty) => { | ||
348 | // The known_ty can't be a type var itself | ||
349 | ty = Cow::Owned(known_ty.clone()); | ||
350 | } | ||
351 | _ => return ty, | ||
352 | } | ||
353 | } | ||
354 | _ => return ty, | ||
355 | } | ||
356 | } | ||
357 | log::error!("Inference variable still not resolved: {:?}", ty); | ||
358 | ty | ||
359 | } | ||
360 | |||
361 | /// Resolves the type as far as currently possible, replacing type variables | ||
362 | /// by their known types. All types returned by the infer_* functions should | ||
363 | /// be resolved as far as possible, i.e. contain no type variables with | ||
364 | /// known type. | ||
365 | fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { | ||
366 | ty.fold(&mut |ty| match ty { | ||
367 | Ty::Infer(tv) => { | ||
368 | let inner = tv.to_inner(); | ||
369 | if tv_stack.contains(&inner) { | ||
370 | mark::hit!(type_var_cycles_resolve_as_possible); | ||
371 | // recursive type | ||
372 | return tv.fallback_value(); | ||
373 | } | ||
374 | if let Some(known_ty) = | ||
375 | self.var_unification_table.inlined_probe_value(inner).known() | ||
376 | { | ||
377 | // known_ty may contain other variables that are known by now | ||
378 | tv_stack.push(inner); | ||
379 | let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone()); | ||
380 | tv_stack.pop(); | ||
381 | result | ||
382 | } else { | ||
383 | ty | ||
384 | } | ||
385 | } | ||
386 | _ => ty, | ||
387 | }) | ||
388 | } | ||
389 | |||
390 | /// Resolves the type completely; type variables without known type are | ||
391 | /// replaced by Ty::Unknown. | ||
392 | fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { | ||
393 | ty.fold(&mut |ty| match ty { | ||
394 | Ty::Infer(tv) => { | ||
395 | let inner = tv.to_inner(); | ||
396 | if tv_stack.contains(&inner) { | ||
397 | mark::hit!(type_var_cycles_resolve_completely); | ||
398 | // recursive type | ||
399 | return tv.fallback_value(); | ||
400 | } | ||
401 | if let Some(known_ty) = | ||
402 | self.var_unification_table.inlined_probe_value(inner).known() | ||
403 | { | ||
404 | // known_ty may contain other variables that are known by now | ||
405 | tv_stack.push(inner); | ||
406 | let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone()); | ||
407 | tv_stack.pop(); | ||
408 | result | ||
409 | } else { | ||
410 | tv.fallback_value() | ||
411 | } | ||
412 | } | ||
413 | _ => ty, | ||
414 | }) | ||
415 | } | ||
416 | } | ||
417 | |||
418 | /// The ID of a type variable. | ||
419 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | ||
420 | pub struct TypeVarId(pub(super) u32); | ||
421 | |||
422 | impl UnifyKey for TypeVarId { | ||
423 | type Value = TypeVarValue; | ||
424 | |||
425 | fn index(&self) -> u32 { | ||
426 | self.0 | ||
427 | } | ||
428 | |||
429 | fn from_index(i: u32) -> Self { | ||
430 | TypeVarId(i) | ||
431 | } | ||
432 | |||
433 | fn tag() -> &'static str { | ||
434 | "TypeVarId" | ||
435 | } | ||
436 | } | ||
437 | |||
438 | /// The value of a type variable: either we already know the type, or we don't | ||
439 | /// know it yet. | ||
440 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
441 | pub enum TypeVarValue { | ||
442 | Known(Ty), | ||
443 | Unknown, | ||
444 | } | ||
445 | |||
446 | impl TypeVarValue { | ||
447 | fn known(&self) -> Option<&Ty> { | ||
448 | match self { | ||
449 | TypeVarValue::Known(ty) => Some(ty), | ||
450 | TypeVarValue::Unknown => None, | ||
451 | } | ||
452 | } | ||
453 | } | ||
454 | |||
455 | impl UnifyValue for TypeVarValue { | ||
456 | type Error = NoError; | ||
457 | |||
458 | fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> { | ||
459 | match (value1, value2) { | ||
460 | // We should never equate two type variables, both of which have | ||
461 | // known types. Instead, we recursively equate those types. | ||
462 | (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!( | ||
463 | "equating two type variables, both of which have known types: {:?} and {:?}", | ||
464 | t1, t2 | ||
465 | ), | ||
466 | |||
467 | // If one side is known, prefer that one. | ||
468 | (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()), | ||
469 | (TypeVarValue::Unknown, TypeVarValue::Known(..)) => Ok(value2.clone()), | ||
470 | |||
471 | (TypeVarValue::Unknown, TypeVarValue::Unknown) => Ok(TypeVarValue::Unknown), | ||
472 | } | ||
473 | } | ||
474 | } | ||
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs new file mode 100644 index 000000000..1e748476a --- /dev/null +++ b/crates/hir_ty/src/lib.rs | |||
@@ -0,0 +1,1078 @@ | |||
1 | //! The type system. We currently use this to infer types for completion, hover | ||
2 | //! information and various assists. | ||
3 | |||
4 | #[allow(unused)] | ||
5 | macro_rules! eprintln { | ||
6 | ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; | ||
7 | } | ||
8 | |||
9 | mod autoderef; | ||
10 | pub mod primitive; | ||
11 | pub mod traits; | ||
12 | pub mod method_resolution; | ||
13 | mod op; | ||
14 | mod lower; | ||
15 | pub(crate) mod infer; | ||
16 | pub(crate) mod utils; | ||
17 | |||
18 | pub mod display; | ||
19 | pub mod db; | ||
20 | pub mod diagnostics; | ||
21 | |||
22 | #[cfg(test)] | ||
23 | mod tests; | ||
24 | #[cfg(test)] | ||
25 | mod test_db; | ||
26 | |||
27 | use std::{iter, mem, ops::Deref, sync::Arc}; | ||
28 | |||
29 | use base_db::{salsa, CrateId}; | ||
30 | use hir_def::{ | ||
31 | expr::ExprId, | ||
32 | type_ref::{Mutability, Rawness}, | ||
33 | AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, | ||
34 | TypeParamId, | ||
35 | }; | ||
36 | use itertools::Itertools; | ||
37 | |||
38 | use crate::{ | ||
39 | db::HirDatabase, | ||
40 | display::HirDisplay, | ||
41 | primitive::{FloatTy, IntTy}, | ||
42 | utils::{generics, make_mut_slice, Generics}, | ||
43 | }; | ||
44 | |||
45 | pub use autoderef::autoderef; | ||
46 | pub use infer::{InferTy, InferenceResult}; | ||
47 | pub use lower::CallableDefId; | ||
48 | pub use lower::{ | ||
49 | associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId, | ||
50 | TyLoweringContext, ValueTyDefId, | ||
51 | }; | ||
52 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | ||
53 | |||
54 | pub use chalk_ir::{BoundVar, DebruijnIndex}; | ||
55 | |||
56 | /// A type constructor or type name: this might be something like the primitive | ||
57 | /// type `bool`, a struct like `Vec`, or things like function pointers or | ||
58 | /// tuples. | ||
59 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] | ||
60 | pub enum TypeCtor { | ||
61 | /// The primitive boolean type. Written as `bool`. | ||
62 | Bool, | ||
63 | |||
64 | /// The primitive character type; holds a Unicode scalar value | ||
65 | /// (a non-surrogate code point). Written as `char`. | ||
66 | Char, | ||
67 | |||
68 | /// A primitive integer type. For example, `i32`. | ||
69 | Int(IntTy), | ||
70 | |||
71 | /// A primitive floating-point type. For example, `f64`. | ||
72 | Float(FloatTy), | ||
73 | |||
74 | /// Structures, enumerations and unions. | ||
75 | Adt(AdtId), | ||
76 | |||
77 | /// The pointee of a string slice. Written as `str`. | ||
78 | Str, | ||
79 | |||
80 | /// The pointee of an array slice. Written as `[T]`. | ||
81 | Slice, | ||
82 | |||
83 | /// An array with the given length. Written as `[T; n]`. | ||
84 | Array, | ||
85 | |||
86 | /// A raw pointer. Written as `*mut T` or `*const T` | ||
87 | RawPtr(Mutability), | ||
88 | |||
89 | /// A reference; a pointer with an associated lifetime. Written as | ||
90 | /// `&'a mut T` or `&'a T`. | ||
91 | Ref(Mutability), | ||
92 | |||
93 | /// The anonymous type of a function declaration/definition. Each | ||
94 | /// function has a unique type, which is output (for a function | ||
95 | /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`. | ||
96 | /// | ||
97 | /// This includes tuple struct / enum variant constructors as well. | ||
98 | /// | ||
99 | /// For example the type of `bar` here: | ||
100 | /// | ||
101 | /// ``` | ||
102 | /// fn foo() -> i32 { 1 } | ||
103 | /// let bar = foo; // bar: fn() -> i32 {foo} | ||
104 | /// ``` | ||
105 | FnDef(CallableDefId), | ||
106 | |||
107 | /// A pointer to a function. Written as `fn() -> i32`. | ||
108 | /// | ||
109 | /// For example the type of `bar` here: | ||
110 | /// | ||
111 | /// ``` | ||
112 | /// fn foo() -> i32 { 1 } | ||
113 | /// let bar: fn() -> i32 = foo; | ||
114 | /// ``` | ||
115 | // FIXME make this a Ty variant like in Chalk | ||
116 | FnPtr { num_args: u16, is_varargs: bool }, | ||
117 | |||
118 | /// The never type `!`. | ||
119 | Never, | ||
120 | |||
121 | /// A tuple type. For example, `(i32, bool)`. | ||
122 | Tuple { cardinality: u16 }, | ||
123 | |||
124 | /// Represents an associated item like `Iterator::Item`. This is used | ||
125 | /// when we have tried to normalize a projection like `T::Item` but | ||
126 | /// couldn't find a better representation. In that case, we generate | ||
127 | /// an **application type** like `(Iterator::Item)<T>`. | ||
128 | AssociatedType(TypeAliasId), | ||
129 | |||
130 | /// This represents a placeholder for an opaque type in situations where we | ||
131 | /// don't know the hidden type (i.e. currently almost always). This is | ||
132 | /// analogous to the `AssociatedType` type constructor. As with that one, | ||
133 | /// these are only produced by Chalk. | ||
134 | OpaqueType(OpaqueTyId), | ||
135 | |||
136 | /// The type of a specific closure. | ||
137 | /// | ||
138 | /// The closure signature is stored in a `FnPtr` type in the first type | ||
139 | /// parameter. | ||
140 | Closure { def: DefWithBodyId, expr: ExprId }, | ||
141 | } | ||
142 | |||
143 | impl TypeCtor { | ||
144 | pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { | ||
145 | match self { | ||
146 | TypeCtor::Bool | ||
147 | | TypeCtor::Char | ||
148 | | TypeCtor::Int(_) | ||
149 | | TypeCtor::Float(_) | ||
150 | | TypeCtor::Str | ||
151 | | TypeCtor::Never => 0, | ||
152 | TypeCtor::Slice | ||
153 | | TypeCtor::Array | ||
154 | | TypeCtor::RawPtr(_) | ||
155 | | TypeCtor::Ref(_) | ||
156 | | TypeCtor::Closure { .. } // 1 param representing the signature of the closure | ||
157 | => 1, | ||
158 | TypeCtor::Adt(adt) => { | ||
159 | let generic_params = generics(db.upcast(), adt.into()); | ||
160 | generic_params.len() | ||
161 | } | ||
162 | TypeCtor::FnDef(callable) => { | ||
163 | let generic_params = generics(db.upcast(), callable.into()); | ||
164 | generic_params.len() | ||
165 | } | ||
166 | TypeCtor::AssociatedType(type_alias) => { | ||
167 | let generic_params = generics(db.upcast(), type_alias.into()); | ||
168 | generic_params.len() | ||
169 | } | ||
170 | TypeCtor::OpaqueType(opaque_ty_id) => { | ||
171 | match opaque_ty_id { | ||
172 | OpaqueTyId::ReturnTypeImplTrait(func, _) => { | ||
173 | let generic_params = generics(db.upcast(), func.into()); | ||
174 | generic_params.len() | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1, | ||
179 | TypeCtor::Tuple { cardinality } => cardinality as usize, | ||
180 | } | ||
181 | } | ||
182 | |||
183 | pub fn krate(self, db: &dyn HirDatabase) -> Option<CrateId> { | ||
184 | match self { | ||
185 | TypeCtor::Bool | ||
186 | | TypeCtor::Char | ||
187 | | TypeCtor::Int(_) | ||
188 | | TypeCtor::Float(_) | ||
189 | | TypeCtor::Str | ||
190 | | TypeCtor::Never | ||
191 | | TypeCtor::Slice | ||
192 | | TypeCtor::Array | ||
193 | | TypeCtor::RawPtr(_) | ||
194 | | TypeCtor::Ref(_) | ||
195 | | TypeCtor::FnPtr { .. } | ||
196 | | TypeCtor::Tuple { .. } => None, | ||
197 | // Closure's krate is irrelevant for coherence I would think? | ||
198 | TypeCtor::Closure { .. } => None, | ||
199 | TypeCtor::Adt(adt) => Some(adt.module(db.upcast()).krate), | ||
200 | TypeCtor::FnDef(callable) => Some(callable.krate(db)), | ||
201 | TypeCtor::AssociatedType(type_alias) => { | ||
202 | Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate) | ||
203 | } | ||
204 | TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id { | ||
205 | OpaqueTyId::ReturnTypeImplTrait(func, _) => { | ||
206 | Some(func.lookup(db.upcast()).module(db.upcast()).krate) | ||
207 | } | ||
208 | }, | ||
209 | } | ||
210 | } | ||
211 | |||
212 | pub fn as_generic_def(self) -> Option<GenericDefId> { | ||
213 | match self { | ||
214 | TypeCtor::Bool | ||
215 | | TypeCtor::Char | ||
216 | | TypeCtor::Int(_) | ||
217 | | TypeCtor::Float(_) | ||
218 | | TypeCtor::Str | ||
219 | | TypeCtor::Never | ||
220 | | TypeCtor::Slice | ||
221 | | TypeCtor::Array | ||
222 | | TypeCtor::RawPtr(_) | ||
223 | | TypeCtor::Ref(_) | ||
224 | | TypeCtor::FnPtr { .. } | ||
225 | | TypeCtor::Tuple { .. } | ||
226 | | TypeCtor::Closure { .. } => None, | ||
227 | TypeCtor::Adt(adt) => Some(adt.into()), | ||
228 | TypeCtor::FnDef(callable) => Some(callable.into()), | ||
229 | TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()), | ||
230 | TypeCtor::OpaqueType(_impl_trait_id) => None, | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | |||
235 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | ||
236 | /// type like `bool`, a struct, tuple, function pointer, reference or | ||
237 | /// several other things. | ||
238 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
239 | pub struct ApplicationTy { | ||
240 | pub ctor: TypeCtor, | ||
241 | pub parameters: Substs, | ||
242 | } | ||
243 | |||
244 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
245 | pub struct OpaqueTy { | ||
246 | pub opaque_ty_id: OpaqueTyId, | ||
247 | pub parameters: Substs, | ||
248 | } | ||
249 | |||
250 | /// A "projection" type corresponds to an (unnormalized) | ||
251 | /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the | ||
252 | /// trait and all its parameters are fully known. | ||
253 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
254 | pub struct ProjectionTy { | ||
255 | pub associated_ty: TypeAliasId, | ||
256 | pub parameters: Substs, | ||
257 | } | ||
258 | |||
259 | impl ProjectionTy { | ||
260 | pub fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef { | ||
261 | TraitRef { trait_: self.trait_(db), substs: self.parameters.clone() } | ||
262 | } | ||
263 | |||
264 | fn trait_(&self, db: &dyn HirDatabase) -> TraitId { | ||
265 | match self.associated_ty.lookup(db.upcast()).container { | ||
266 | AssocContainerId::TraitId(it) => it, | ||
267 | _ => panic!("projection ty without parent trait"), | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | impl TypeWalk for ProjectionTy { | ||
273 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
274 | self.parameters.walk(f); | ||
275 | } | ||
276 | |||
277 | fn walk_mut_binders( | ||
278 | &mut self, | ||
279 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
280 | binders: DebruijnIndex, | ||
281 | ) { | ||
282 | self.parameters.walk_mut_binders(f, binders); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | /// A type. | ||
287 | /// | ||
288 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents | ||
289 | /// the same thing (but in a different way). | ||
290 | /// | ||
291 | /// This should be cheap to clone. | ||
292 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
293 | pub enum Ty { | ||
294 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | ||
295 | /// type like `bool`, a struct, tuple, function pointer, reference or | ||
296 | /// several other things. | ||
297 | Apply(ApplicationTy), | ||
298 | |||
299 | /// A "projection" type corresponds to an (unnormalized) | ||
300 | /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the | ||
301 | /// trait and all its parameters are fully known. | ||
302 | Projection(ProjectionTy), | ||
303 | |||
304 | /// An opaque type (`impl Trait`). | ||
305 | /// | ||
306 | /// This is currently only used for return type impl trait; each instance of | ||
307 | /// `impl Trait` in a return type gets its own ID. | ||
308 | Opaque(OpaqueTy), | ||
309 | |||
310 | /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T) | ||
311 | /// {}` when we're type-checking the body of that function. In this | ||
312 | /// situation, we know this stands for *some* type, but don't know the exact | ||
313 | /// type. | ||
314 | Placeholder(TypeParamId), | ||
315 | |||
316 | /// A bound type variable. This is used in various places: when representing | ||
317 | /// some polymorphic type like the type of function `fn f<T>`, the type | ||
318 | /// parameters get turned into variables; during trait resolution, inference | ||
319 | /// variables get turned into bound variables and back; and in `Dyn` the | ||
320 | /// `Self` type is represented with a bound variable as well. | ||
321 | Bound(BoundVar), | ||
322 | |||
323 | /// A type variable used during type checking. | ||
324 | Infer(InferTy), | ||
325 | |||
326 | /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust). | ||
327 | /// | ||
328 | /// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)` | ||
329 | /// represents the `Self` type inside the bounds. This is currently | ||
330 | /// implicit; Chalk has the `Binders` struct to make it explicit, but it | ||
331 | /// didn't seem worth the overhead yet. | ||
332 | Dyn(Arc<[GenericPredicate]>), | ||
333 | |||
334 | /// A placeholder for a type which could not be computed; this is propagated | ||
335 | /// to avoid useless error messages. Doubles as a placeholder where type | ||
336 | /// variables are inserted before type checking, since we want to try to | ||
337 | /// infer a better type here anyway -- for the IDE use case, we want to try | ||
338 | /// to infer as much as possible even in the presence of type errors. | ||
339 | Unknown, | ||
340 | } | ||
341 | |||
342 | /// A list of substitutions for generic parameters. | ||
343 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
344 | pub struct Substs(Arc<[Ty]>); | ||
345 | |||
346 | impl TypeWalk for Substs { | ||
347 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
348 | for t in self.0.iter() { | ||
349 | t.walk(f); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | fn walk_mut_binders( | ||
354 | &mut self, | ||
355 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
356 | binders: DebruijnIndex, | ||
357 | ) { | ||
358 | for t in make_mut_slice(&mut self.0) { | ||
359 | t.walk_mut_binders(f, binders); | ||
360 | } | ||
361 | } | ||
362 | } | ||
363 | |||
364 | impl Substs { | ||
365 | pub fn empty() -> Substs { | ||
366 | Substs(Arc::new([])) | ||
367 | } | ||
368 | |||
369 | pub fn single(ty: Ty) -> Substs { | ||
370 | Substs(Arc::new([ty])) | ||
371 | } | ||
372 | |||
373 | pub fn prefix(&self, n: usize) -> Substs { | ||
374 | Substs(self.0[..std::cmp::min(self.0.len(), n)].into()) | ||
375 | } | ||
376 | |||
377 | pub fn suffix(&self, n: usize) -> Substs { | ||
378 | Substs(self.0[self.0.len() - std::cmp::min(self.0.len(), n)..].into()) | ||
379 | } | ||
380 | |||
381 | pub fn as_single(&self) -> &Ty { | ||
382 | if self.0.len() != 1 { | ||
383 | panic!("expected substs of len 1, got {:?}", self); | ||
384 | } | ||
385 | &self.0[0] | ||
386 | } | ||
387 | |||
388 | /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). | ||
389 | pub(crate) fn type_params_for_generics(generic_params: &Generics) -> Substs { | ||
390 | Substs(generic_params.iter().map(|(id, _)| Ty::Placeholder(id)).collect()) | ||
391 | } | ||
392 | |||
393 | /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). | ||
394 | pub fn type_params(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substs { | ||
395 | let params = generics(db.upcast(), def.into()); | ||
396 | Substs::type_params_for_generics(¶ms) | ||
397 | } | ||
398 | |||
399 | /// Return Substs that replace each parameter by a bound variable. | ||
400 | pub(crate) fn bound_vars(generic_params: &Generics, debruijn: DebruijnIndex) -> Substs { | ||
401 | Substs( | ||
402 | generic_params | ||
403 | .iter() | ||
404 | .enumerate() | ||
405 | .map(|(idx, _)| Ty::Bound(BoundVar::new(debruijn, idx))) | ||
406 | .collect(), | ||
407 | ) | ||
408 | } | ||
409 | |||
410 | pub fn build_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder { | ||
411 | let def = def.into(); | ||
412 | let params = generics(db.upcast(), def); | ||
413 | let param_count = params.len(); | ||
414 | Substs::builder(param_count) | ||
415 | } | ||
416 | |||
417 | pub(crate) fn build_for_generics(generic_params: &Generics) -> SubstsBuilder { | ||
418 | Substs::builder(generic_params.len()) | ||
419 | } | ||
420 | |||
421 | pub fn build_for_type_ctor(db: &dyn HirDatabase, type_ctor: TypeCtor) -> SubstsBuilder { | ||
422 | Substs::builder(type_ctor.num_ty_params(db)) | ||
423 | } | ||
424 | |||
425 | fn builder(param_count: usize) -> SubstsBuilder { | ||
426 | SubstsBuilder { vec: Vec::with_capacity(param_count), param_count } | ||
427 | } | ||
428 | } | ||
429 | |||
430 | /// Return an index of a parameter in the generic type parameter list by it's id. | ||
431 | pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> { | ||
432 | generics(db.upcast(), id.parent).param_idx(id) | ||
433 | } | ||
434 | |||
435 | #[derive(Debug, Clone)] | ||
436 | pub struct SubstsBuilder { | ||
437 | vec: Vec<Ty>, | ||
438 | param_count: usize, | ||
439 | } | ||
440 | |||
441 | impl SubstsBuilder { | ||
442 | pub fn build(self) -> Substs { | ||
443 | assert_eq!(self.vec.len(), self.param_count); | ||
444 | Substs(self.vec.into()) | ||
445 | } | ||
446 | |||
447 | pub fn push(mut self, ty: Ty) -> Self { | ||
448 | self.vec.push(ty); | ||
449 | self | ||
450 | } | ||
451 | |||
452 | fn remaining(&self) -> usize { | ||
453 | self.param_count - self.vec.len() | ||
454 | } | ||
455 | |||
456 | pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self { | ||
457 | self.fill((starting_from..).map(|idx| Ty::Bound(BoundVar::new(debruijn, idx)))) | ||
458 | } | ||
459 | |||
460 | pub fn fill_with_unknown(self) -> Self { | ||
461 | self.fill(iter::repeat(Ty::Unknown)) | ||
462 | } | ||
463 | |||
464 | pub fn fill(mut self, filler: impl Iterator<Item = Ty>) -> Self { | ||
465 | self.vec.extend(filler.take(self.remaining())); | ||
466 | assert_eq!(self.remaining(), 0); | ||
467 | self | ||
468 | } | ||
469 | |||
470 | pub fn use_parent_substs(mut self, parent_substs: &Substs) -> Self { | ||
471 | assert!(self.vec.is_empty()); | ||
472 | assert!(parent_substs.len() <= self.param_count); | ||
473 | self.vec.extend(parent_substs.iter().cloned()); | ||
474 | self | ||
475 | } | ||
476 | } | ||
477 | |||
478 | impl Deref for Substs { | ||
479 | type Target = [Ty]; | ||
480 | |||
481 | fn deref(&self) -> &[Ty] { | ||
482 | &self.0 | ||
483 | } | ||
484 | } | ||
485 | |||
486 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] | ||
487 | pub struct Binders<T> { | ||
488 | pub num_binders: usize, | ||
489 | pub value: T, | ||
490 | } | ||
491 | |||
492 | impl<T> Binders<T> { | ||
493 | pub fn new(num_binders: usize, value: T) -> Self { | ||
494 | Self { num_binders, value } | ||
495 | } | ||
496 | |||
497 | pub fn as_ref(&self) -> Binders<&T> { | ||
498 | Binders { num_binders: self.num_binders, value: &self.value } | ||
499 | } | ||
500 | |||
501 | pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> { | ||
502 | Binders { num_binders: self.num_binders, value: f(self.value) } | ||
503 | } | ||
504 | |||
505 | pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> { | ||
506 | Some(Binders { num_binders: self.num_binders, value: f(self.value)? }) | ||
507 | } | ||
508 | } | ||
509 | |||
510 | impl<T: Clone> Binders<&T> { | ||
511 | pub fn cloned(&self) -> Binders<T> { | ||
512 | Binders { num_binders: self.num_binders, value: self.value.clone() } | ||
513 | } | ||
514 | } | ||
515 | |||
516 | impl<T: TypeWalk> Binders<T> { | ||
517 | /// Substitutes all variables. | ||
518 | pub fn subst(self, subst: &Substs) -> T { | ||
519 | assert_eq!(subst.len(), self.num_binders); | ||
520 | self.value.subst_bound_vars(subst) | ||
521 | } | ||
522 | |||
523 | /// Substitutes just a prefix of the variables (shifting the rest). | ||
524 | pub fn subst_prefix(self, subst: &Substs) -> Binders<T> { | ||
525 | assert!(subst.len() < self.num_binders); | ||
526 | Binders::new(self.num_binders - subst.len(), self.value.subst_bound_vars(subst)) | ||
527 | } | ||
528 | } | ||
529 | |||
530 | impl<T: TypeWalk> TypeWalk for Binders<T> { | ||
531 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
532 | self.value.walk(f); | ||
533 | } | ||
534 | |||
535 | fn walk_mut_binders( | ||
536 | &mut self, | ||
537 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
538 | binders: DebruijnIndex, | ||
539 | ) { | ||
540 | self.value.walk_mut_binders(f, binders.shifted_in()) | ||
541 | } | ||
542 | } | ||
543 | |||
544 | /// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. | ||
545 | /// Name to be bikeshedded: TraitBound? TraitImplements? | ||
546 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
547 | pub struct TraitRef { | ||
548 | /// FIXME name? | ||
549 | pub trait_: TraitId, | ||
550 | pub substs: Substs, | ||
551 | } | ||
552 | |||
553 | impl TraitRef { | ||
554 | pub fn self_ty(&self) -> &Ty { | ||
555 | &self.substs[0] | ||
556 | } | ||
557 | } | ||
558 | |||
559 | impl TypeWalk for TraitRef { | ||
560 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
561 | self.substs.walk(f); | ||
562 | } | ||
563 | |||
564 | fn walk_mut_binders( | ||
565 | &mut self, | ||
566 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
567 | binders: DebruijnIndex, | ||
568 | ) { | ||
569 | self.substs.walk_mut_binders(f, binders); | ||
570 | } | ||
571 | } | ||
572 | |||
573 | /// Like `generics::WherePredicate`, but with resolved types: A condition on the | ||
574 | /// parameters of a generic item. | ||
575 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
576 | pub enum GenericPredicate { | ||
577 | /// The given trait needs to be implemented for its type parameters. | ||
578 | Implemented(TraitRef), | ||
579 | /// An associated type bindings like in `Iterator<Item = T>`. | ||
580 | Projection(ProjectionPredicate), | ||
581 | /// We couldn't resolve the trait reference. (If some type parameters can't | ||
582 | /// be resolved, they will just be Unknown). | ||
583 | Error, | ||
584 | } | ||
585 | |||
586 | impl GenericPredicate { | ||
587 | pub fn is_error(&self) -> bool { | ||
588 | matches!(self, GenericPredicate::Error) | ||
589 | } | ||
590 | |||
591 | pub fn is_implemented(&self) -> bool { | ||
592 | matches!(self, GenericPredicate::Implemented(_)) | ||
593 | } | ||
594 | |||
595 | pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> { | ||
596 | match self { | ||
597 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | ||
598 | GenericPredicate::Projection(proj) => Some(proj.projection_ty.trait_ref(db)), | ||
599 | GenericPredicate::Error => None, | ||
600 | } | ||
601 | } | ||
602 | } | ||
603 | |||
604 | impl TypeWalk for GenericPredicate { | ||
605 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
606 | match self { | ||
607 | GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f), | ||
608 | GenericPredicate::Projection(projection_pred) => projection_pred.walk(f), | ||
609 | GenericPredicate::Error => {} | ||
610 | } | ||
611 | } | ||
612 | |||
613 | fn walk_mut_binders( | ||
614 | &mut self, | ||
615 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
616 | binders: DebruijnIndex, | ||
617 | ) { | ||
618 | match self { | ||
619 | GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders), | ||
620 | GenericPredicate::Projection(projection_pred) => { | ||
621 | projection_pred.walk_mut_binders(f, binders) | ||
622 | } | ||
623 | GenericPredicate::Error => {} | ||
624 | } | ||
625 | } | ||
626 | } | ||
627 | |||
628 | /// Basically a claim (currently not validated / checked) that the contained | ||
629 | /// type / trait ref contains no inference variables; any inference variables it | ||
630 | /// contained have been replaced by bound variables, and `kinds` tells us how | ||
631 | /// many there are and whether they were normal or float/int variables. This is | ||
632 | /// used to erase irrelevant differences between types before using them in | ||
633 | /// queries. | ||
634 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
635 | pub struct Canonical<T> { | ||
636 | pub value: T, | ||
637 | pub kinds: Arc<[TyKind]>, | ||
638 | } | ||
639 | |||
640 | impl<T> Canonical<T> { | ||
641 | pub fn new(value: T, kinds: impl IntoIterator<Item = TyKind>) -> Self { | ||
642 | Self { value, kinds: kinds.into_iter().collect() } | ||
643 | } | ||
644 | } | ||
645 | |||
646 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
647 | pub enum TyKind { | ||
648 | General, | ||
649 | Integer, | ||
650 | Float, | ||
651 | } | ||
652 | |||
653 | /// A function signature as seen by type inference: Several parameter types and | ||
654 | /// one return type. | ||
655 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
656 | pub struct FnSig { | ||
657 | params_and_return: Arc<[Ty]>, | ||
658 | is_varargs: bool, | ||
659 | } | ||
660 | |||
661 | /// A polymorphic function signature. | ||
662 | pub type PolyFnSig = Binders<FnSig>; | ||
663 | |||
664 | impl FnSig { | ||
665 | pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> FnSig { | ||
666 | params.push(ret); | ||
667 | FnSig { params_and_return: params.into(), is_varargs } | ||
668 | } | ||
669 | |||
670 | pub fn from_fn_ptr_substs(substs: &Substs, is_varargs: bool) -> FnSig { | ||
671 | FnSig { params_and_return: Arc::clone(&substs.0), is_varargs } | ||
672 | } | ||
673 | |||
674 | pub fn params(&self) -> &[Ty] { | ||
675 | &self.params_and_return[0..self.params_and_return.len() - 1] | ||
676 | } | ||
677 | |||
678 | pub fn ret(&self) -> &Ty { | ||
679 | &self.params_and_return[self.params_and_return.len() - 1] | ||
680 | } | ||
681 | } | ||
682 | |||
683 | impl TypeWalk for FnSig { | ||
684 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
685 | for t in self.params_and_return.iter() { | ||
686 | t.walk(f); | ||
687 | } | ||
688 | } | ||
689 | |||
690 | fn walk_mut_binders( | ||
691 | &mut self, | ||
692 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
693 | binders: DebruijnIndex, | ||
694 | ) { | ||
695 | for t in make_mut_slice(&mut self.params_and_return) { | ||
696 | t.walk_mut_binders(f, binders); | ||
697 | } | ||
698 | } | ||
699 | } | ||
700 | |||
701 | impl Ty { | ||
702 | pub fn simple(ctor: TypeCtor) -> Ty { | ||
703 | Ty::Apply(ApplicationTy { ctor, parameters: Substs::empty() }) | ||
704 | } | ||
705 | pub fn apply_one(ctor: TypeCtor, param: Ty) -> Ty { | ||
706 | Ty::Apply(ApplicationTy { ctor, parameters: Substs::single(param) }) | ||
707 | } | ||
708 | pub fn apply(ctor: TypeCtor, parameters: Substs) -> Ty { | ||
709 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
710 | } | ||
711 | pub fn unit() -> Self { | ||
712 | Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) | ||
713 | } | ||
714 | pub fn fn_ptr(sig: FnSig) -> Self { | ||
715 | Ty::apply( | ||
716 | TypeCtor::FnPtr { num_args: sig.params().len() as u16, is_varargs: sig.is_varargs }, | ||
717 | Substs(sig.params_and_return), | ||
718 | ) | ||
719 | } | ||
720 | |||
721 | pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { | ||
722 | match self { | ||
723 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { | ||
724 | Some((parameters.as_single(), *mutability)) | ||
725 | } | ||
726 | _ => None, | ||
727 | } | ||
728 | } | ||
729 | |||
730 | pub fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> { | ||
731 | match self { | ||
732 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { | ||
733 | Some((parameters.as_single(), Rawness::Ref, *mutability)) | ||
734 | } | ||
735 | Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(mutability), parameters }) => { | ||
736 | Some((parameters.as_single(), Rawness::RawPtr, *mutability)) | ||
737 | } | ||
738 | _ => None, | ||
739 | } | ||
740 | } | ||
741 | |||
742 | pub fn strip_references(&self) -> &Ty { | ||
743 | let mut t: &Ty = self; | ||
744 | |||
745 | while let Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(_mutability), parameters }) = t { | ||
746 | t = parameters.as_single(); | ||
747 | } | ||
748 | |||
749 | t | ||
750 | } | ||
751 | |||
752 | pub fn as_adt(&self) -> Option<(AdtId, &Substs)> { | ||
753 | match self { | ||
754 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_def), parameters }) => { | ||
755 | Some((*adt_def, parameters)) | ||
756 | } | ||
757 | _ => None, | ||
758 | } | ||
759 | } | ||
760 | |||
761 | pub fn as_tuple(&self) -> Option<&Substs> { | ||
762 | match self { | ||
763 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Tuple { .. }, parameters }) => { | ||
764 | Some(parameters) | ||
765 | } | ||
766 | _ => None, | ||
767 | } | ||
768 | } | ||
769 | |||
770 | pub fn is_never(&self) -> bool { | ||
771 | matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) | ||
772 | } | ||
773 | |||
774 | /// If this is a `dyn Trait` type, this returns the `Trait` part. | ||
775 | pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { | ||
776 | match self { | ||
777 | Ty::Dyn(bounds) => bounds.get(0).and_then(|b| match b { | ||
778 | GenericPredicate::Implemented(trait_ref) => Some(trait_ref), | ||
779 | _ => None, | ||
780 | }), | ||
781 | _ => None, | ||
782 | } | ||
783 | } | ||
784 | |||
785 | /// If this is a `dyn Trait`, returns that trait. | ||
786 | pub fn dyn_trait(&self) -> Option<TraitId> { | ||
787 | self.dyn_trait_ref().map(|it| it.trait_) | ||
788 | } | ||
789 | |||
790 | fn builtin_deref(&self) -> Option<Ty> { | ||
791 | match self { | ||
792 | Ty::Apply(a_ty) => match a_ty.ctor { | ||
793 | TypeCtor::Ref(..) => Some(Ty::clone(a_ty.parameters.as_single())), | ||
794 | TypeCtor::RawPtr(..) => Some(Ty::clone(a_ty.parameters.as_single())), | ||
795 | _ => None, | ||
796 | }, | ||
797 | _ => None, | ||
798 | } | ||
799 | } | ||
800 | |||
801 | pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> { | ||
802 | match self { | ||
803 | Ty::Apply(a_ty) => match a_ty.ctor { | ||
804 | TypeCtor::FnPtr { is_varargs, .. } => { | ||
805 | Some(FnSig::from_fn_ptr_substs(&a_ty.parameters, is_varargs)) | ||
806 | } | ||
807 | TypeCtor::FnDef(def) => { | ||
808 | let sig = db.callable_item_signature(def); | ||
809 | Some(sig.subst(&a_ty.parameters)) | ||
810 | } | ||
811 | TypeCtor::Closure { .. } => { | ||
812 | let sig_param = &a_ty.parameters[0]; | ||
813 | sig_param.callable_sig(db) | ||
814 | } | ||
815 | _ => None, | ||
816 | }, | ||
817 | _ => None, | ||
818 | } | ||
819 | } | ||
820 | |||
821 | /// If this is a type with type parameters (an ADT or function), replaces | ||
822 | /// the `Substs` for these type parameters with the given ones. (So e.g. if | ||
823 | /// `self` is `Option<_>` and the substs contain `u32`, we'll have | ||
824 | /// `Option<u32>` afterwards.) | ||
825 | pub fn apply_substs(self, substs: Substs) -> Ty { | ||
826 | match self { | ||
827 | Ty::Apply(ApplicationTy { ctor, parameters: previous_substs }) => { | ||
828 | assert_eq!(previous_substs.len(), substs.len()); | ||
829 | Ty::Apply(ApplicationTy { ctor, parameters: substs }) | ||
830 | } | ||
831 | _ => self, | ||
832 | } | ||
833 | } | ||
834 | |||
835 | /// Returns the type parameters of this type if it has some (i.e. is an ADT | ||
836 | /// or function); so if `self` is `Option<u32>`, this returns the `u32`. | ||
837 | pub fn substs(&self) -> Option<Substs> { | ||
838 | match self { | ||
839 | Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()), | ||
840 | _ => None, | ||
841 | } | ||
842 | } | ||
843 | |||
844 | pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> { | ||
845 | match self { | ||
846 | Ty::Opaque(opaque_ty) => { | ||
847 | let predicates = match opaque_ty.opaque_ty_id { | ||
848 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | ||
849 | db.return_type_impl_traits(func).map(|it| { | ||
850 | let data = (*it) | ||
851 | .as_ref() | ||
852 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | ||
853 | data.subst(&opaque_ty.parameters) | ||
854 | }) | ||
855 | } | ||
856 | }; | ||
857 | |||
858 | predicates.map(|it| it.value) | ||
859 | } | ||
860 | Ty::Placeholder(id) => { | ||
861 | let generic_params = db.generic_params(id.parent); | ||
862 | let param_data = &generic_params.types[id.local_id]; | ||
863 | match param_data.provenance { | ||
864 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { | ||
865 | let predicates = db | ||
866 | .generic_predicates_for_param(*id) | ||
867 | .into_iter() | ||
868 | .map(|pred| pred.value.clone()) | ||
869 | .collect_vec(); | ||
870 | |||
871 | Some(predicates) | ||
872 | } | ||
873 | _ => None, | ||
874 | } | ||
875 | } | ||
876 | _ => None, | ||
877 | } | ||
878 | } | ||
879 | |||
880 | pub fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> { | ||
881 | match self { | ||
882 | Ty::Apply(ApplicationTy { ctor: TypeCtor::AssociatedType(type_alias_id), .. }) => { | ||
883 | match type_alias_id.lookup(db.upcast()).container { | ||
884 | AssocContainerId::TraitId(trait_id) => Some(trait_id), | ||
885 | _ => None, | ||
886 | } | ||
887 | } | ||
888 | Ty::Projection(projection_ty) => { | ||
889 | match projection_ty.associated_ty.lookup(db.upcast()).container { | ||
890 | AssocContainerId::TraitId(trait_id) => Some(trait_id), | ||
891 | _ => None, | ||
892 | } | ||
893 | } | ||
894 | _ => None, | ||
895 | } | ||
896 | } | ||
897 | } | ||
898 | |||
899 | /// This allows walking structures that contain types to do something with those | ||
900 | /// types, similar to Chalk's `Fold` trait. | ||
901 | pub trait TypeWalk { | ||
902 | fn walk(&self, f: &mut impl FnMut(&Ty)); | ||
903 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
904 | self.walk_mut_binders(&mut |ty, _binders| f(ty), DebruijnIndex::INNERMOST); | ||
905 | } | ||
906 | /// Walk the type, counting entered binders. | ||
907 | /// | ||
908 | /// `Ty::Bound` variables use DeBruijn indexing, which means that 0 refers | ||
909 | /// to the innermost binder, 1 to the next, etc.. So when we want to | ||
910 | /// substitute a certain bound variable, we can't just walk the whole type | ||
911 | /// and blindly replace each instance of a certain index; when we 'enter' | ||
912 | /// things that introduce new bound variables, we have to keep track of | ||
913 | /// that. Currently, the only thing that introduces bound variables on our | ||
914 | /// side are `Ty::Dyn` and `Ty::Opaque`, which each introduce a bound | ||
915 | /// variable for the self type. | ||
916 | fn walk_mut_binders( | ||
917 | &mut self, | ||
918 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
919 | binders: DebruijnIndex, | ||
920 | ); | ||
921 | |||
922 | fn fold_binders( | ||
923 | mut self, | ||
924 | f: &mut impl FnMut(Ty, DebruijnIndex) -> Ty, | ||
925 | binders: DebruijnIndex, | ||
926 | ) -> Self | ||
927 | where | ||
928 | Self: Sized, | ||
929 | { | ||
930 | self.walk_mut_binders( | ||
931 | &mut |ty_mut, binders| { | ||
932 | let ty = mem::replace(ty_mut, Ty::Unknown); | ||
933 | *ty_mut = f(ty, binders); | ||
934 | }, | ||
935 | binders, | ||
936 | ); | ||
937 | self | ||
938 | } | ||
939 | |||
940 | fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self | ||
941 | where | ||
942 | Self: Sized, | ||
943 | { | ||
944 | self.walk_mut(&mut |ty_mut| { | ||
945 | let ty = mem::replace(ty_mut, Ty::Unknown); | ||
946 | *ty_mut = f(ty); | ||
947 | }); | ||
948 | self | ||
949 | } | ||
950 | |||
951 | /// Substitutes `Ty::Bound` vars with the given substitution. | ||
952 | fn subst_bound_vars(self, substs: &Substs) -> Self | ||
953 | where | ||
954 | Self: Sized, | ||
955 | { | ||
956 | self.subst_bound_vars_at_depth(substs, DebruijnIndex::INNERMOST) | ||
957 | } | ||
958 | |||
959 | /// Substitutes `Ty::Bound` vars with the given substitution. | ||
960 | fn subst_bound_vars_at_depth(mut self, substs: &Substs, depth: DebruijnIndex) -> Self | ||
961 | where | ||
962 | Self: Sized, | ||
963 | { | ||
964 | self.walk_mut_binders( | ||
965 | &mut |ty, binders| { | ||
966 | if let &mut Ty::Bound(bound) = ty { | ||
967 | if bound.debruijn >= binders { | ||
968 | *ty = substs.0[bound.index].clone().shift_bound_vars(binders); | ||
969 | } | ||
970 | } | ||
971 | }, | ||
972 | depth, | ||
973 | ); | ||
974 | self | ||
975 | } | ||
976 | |||
977 | /// Shifts up debruijn indices of `Ty::Bound` vars by `n`. | ||
978 | fn shift_bound_vars(self, n: DebruijnIndex) -> Self | ||
979 | where | ||
980 | Self: Sized, | ||
981 | { | ||
982 | self.fold_binders( | ||
983 | &mut |ty, binders| match ty { | ||
984 | Ty::Bound(bound) if bound.debruijn >= binders => { | ||
985 | Ty::Bound(bound.shifted_in_from(n)) | ||
986 | } | ||
987 | ty => ty, | ||
988 | }, | ||
989 | DebruijnIndex::INNERMOST, | ||
990 | ) | ||
991 | } | ||
992 | } | ||
993 | |||
994 | impl TypeWalk for Ty { | ||
995 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
996 | match self { | ||
997 | Ty::Apply(a_ty) => { | ||
998 | for t in a_ty.parameters.iter() { | ||
999 | t.walk(f); | ||
1000 | } | ||
1001 | } | ||
1002 | Ty::Projection(p_ty) => { | ||
1003 | for t in p_ty.parameters.iter() { | ||
1004 | t.walk(f); | ||
1005 | } | ||
1006 | } | ||
1007 | Ty::Dyn(predicates) => { | ||
1008 | for p in predicates.iter() { | ||
1009 | p.walk(f); | ||
1010 | } | ||
1011 | } | ||
1012 | Ty::Opaque(o_ty) => { | ||
1013 | for t in o_ty.parameters.iter() { | ||
1014 | t.walk(f); | ||
1015 | } | ||
1016 | } | ||
1017 | Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | ||
1018 | } | ||
1019 | f(self); | ||
1020 | } | ||
1021 | |||
1022 | fn walk_mut_binders( | ||
1023 | &mut self, | ||
1024 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
1025 | binders: DebruijnIndex, | ||
1026 | ) { | ||
1027 | match self { | ||
1028 | Ty::Apply(a_ty) => { | ||
1029 | a_ty.parameters.walk_mut_binders(f, binders); | ||
1030 | } | ||
1031 | Ty::Projection(p_ty) => { | ||
1032 | p_ty.parameters.walk_mut_binders(f, binders); | ||
1033 | } | ||
1034 | Ty::Dyn(predicates) => { | ||
1035 | for p in make_mut_slice(predicates) { | ||
1036 | p.walk_mut_binders(f, binders.shifted_in()); | ||
1037 | } | ||
1038 | } | ||
1039 | Ty::Opaque(o_ty) => { | ||
1040 | o_ty.parameters.walk_mut_binders(f, binders); | ||
1041 | } | ||
1042 | Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | ||
1043 | } | ||
1044 | f(self, binders); | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1048 | impl<T: TypeWalk> TypeWalk for Vec<T> { | ||
1049 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
1050 | for t in self { | ||
1051 | t.walk(f); | ||
1052 | } | ||
1053 | } | ||
1054 | fn walk_mut_binders( | ||
1055 | &mut self, | ||
1056 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
1057 | binders: DebruijnIndex, | ||
1058 | ) { | ||
1059 | for t in self { | ||
1060 | t.walk_mut_binders(f, binders); | ||
1061 | } | ||
1062 | } | ||
1063 | } | ||
1064 | |||
1065 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] | ||
1066 | pub enum OpaqueTyId { | ||
1067 | ReturnTypeImplTrait(hir_def::FunctionId, u16), | ||
1068 | } | ||
1069 | |||
1070 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
1071 | pub struct ReturnTypeImplTraits { | ||
1072 | pub(crate) impl_traits: Vec<ReturnTypeImplTrait>, | ||
1073 | } | ||
1074 | |||
1075 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
1076 | pub(crate) struct ReturnTypeImplTrait { | ||
1077 | pub bounds: Binders<Vec<GenericPredicate>>, | ||
1078 | } | ||
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs new file mode 100644 index 000000000..cd574e983 --- /dev/null +++ b/crates/hir_ty/src/lower.rs | |||
@@ -0,0 +1,1242 @@ | |||
1 | //! Methods for lowering the HIR to types. There are two main cases here: | ||
2 | //! | ||
3 | //! - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a | ||
4 | //! type: The entry point for this is `Ty::from_hir`. | ||
5 | //! - Building the type for an item: This happens through the `type_for_def` query. | ||
6 | //! | ||
7 | //! This usually involves resolving names, collecting generic arguments etc. | ||
8 | use std::{iter, sync::Arc}; | ||
9 | |||
10 | use arena::map::ArenaMap; | ||
11 | use base_db::CrateId; | ||
12 | use hir_def::{ | ||
13 | adt::StructKind, | ||
14 | builtin_type::BuiltinType, | ||
15 | generics::{TypeParamProvenance, WherePredicate, WherePredicateTarget}, | ||
16 | path::{GenericArg, Path, PathSegment, PathSegments}, | ||
17 | resolver::{HasResolver, Resolver, TypeNs}, | ||
18 | type_ref::{TypeBound, TypeRef}, | ||
19 | AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, | ||
20 | HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, | ||
21 | UnionId, VariantId, | ||
22 | }; | ||
23 | use hir_expand::name::Name; | ||
24 | use smallvec::SmallVec; | ||
25 | use stdx::impl_from; | ||
26 | use test_utils::mark; | ||
27 | |||
28 | use crate::{ | ||
29 | db::HirDatabase, | ||
30 | primitive::{FloatTy, IntTy}, | ||
31 | utils::{ | ||
32 | all_super_trait_refs, associated_type_by_name_including_super_traits, generics, | ||
33 | make_mut_slice, variant_data, | ||
34 | }, | ||
35 | Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, OpaqueTy, OpaqueTyId, PolyFnSig, | ||
36 | ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, ReturnTypeImplTraits, Substs, | ||
37 | TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, | ||
38 | }; | ||
39 | |||
40 | #[derive(Debug)] | ||
41 | pub struct TyLoweringContext<'a> { | ||
42 | pub db: &'a dyn HirDatabase, | ||
43 | pub resolver: &'a Resolver, | ||
44 | in_binders: DebruijnIndex, | ||
45 | /// Note: Conceptually, it's thinkable that we could be in a location where | ||
46 | /// some type params should be represented as placeholders, and others | ||
47 | /// should be converted to variables. I think in practice, this isn't | ||
48 | /// possible currently, so this should be fine for now. | ||
49 | pub type_param_mode: TypeParamLoweringMode, | ||
50 | pub impl_trait_mode: ImplTraitLoweringMode, | ||
51 | impl_trait_counter: std::cell::Cell<u16>, | ||
52 | /// When turning `impl Trait` into opaque types, we have to collect the | ||
53 | /// bounds at the same time to get the IDs correct (without becoming too | ||
54 | /// complicated). I don't like using interior mutability (as for the | ||
55 | /// counter), but I've tried and failed to make the lifetimes work for | ||
56 | /// passing around a `&mut TyLoweringContext`. The core problem is that | ||
57 | /// we're grouping the mutable data (the counter and this field) together | ||
58 | /// with the immutable context (the references to the DB and resolver). | ||
59 | /// Splitting this up would be a possible fix. | ||
60 | opaque_type_data: std::cell::RefCell<Vec<ReturnTypeImplTrait>>, | ||
61 | } | ||
62 | |||
63 | impl<'a> TyLoweringContext<'a> { | ||
64 | pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { | ||
65 | let impl_trait_counter = std::cell::Cell::new(0); | ||
66 | let impl_trait_mode = ImplTraitLoweringMode::Disallowed; | ||
67 | let type_param_mode = TypeParamLoweringMode::Placeholder; | ||
68 | let in_binders = DebruijnIndex::INNERMOST; | ||
69 | let opaque_type_data = std::cell::RefCell::new(Vec::new()); | ||
70 | Self { | ||
71 | db, | ||
72 | resolver, | ||
73 | in_binders, | ||
74 | impl_trait_mode, | ||
75 | impl_trait_counter, | ||
76 | type_param_mode, | ||
77 | opaque_type_data, | ||
78 | } | ||
79 | } | ||
80 | |||
81 | pub fn with_debruijn<T>( | ||
82 | &self, | ||
83 | debruijn: DebruijnIndex, | ||
84 | f: impl FnOnce(&TyLoweringContext) -> T, | ||
85 | ) -> T { | ||
86 | let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new()); | ||
87 | let new_ctx = Self { | ||
88 | in_binders: debruijn, | ||
89 | impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), | ||
90 | opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec), | ||
91 | ..*self | ||
92 | }; | ||
93 | let result = f(&new_ctx); | ||
94 | self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); | ||
95 | self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); | ||
96 | result | ||
97 | } | ||
98 | |||
99 | pub fn with_shifted_in<T>( | ||
100 | &self, | ||
101 | debruijn: DebruijnIndex, | ||
102 | f: impl FnOnce(&TyLoweringContext) -> T, | ||
103 | ) -> T { | ||
104 | self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f) | ||
105 | } | ||
106 | |||
107 | pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { | ||
108 | Self { impl_trait_mode, ..self } | ||
109 | } | ||
110 | |||
111 | pub fn with_type_param_mode(self, type_param_mode: TypeParamLoweringMode) -> Self { | ||
112 | Self { type_param_mode, ..self } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
117 | pub enum ImplTraitLoweringMode { | ||
118 | /// `impl Trait` gets lowered into an opaque type that doesn't unify with | ||
119 | /// anything except itself. This is used in places where values flow 'out', | ||
120 | /// i.e. for arguments of the function we're currently checking, and return | ||
121 | /// types of functions we're calling. | ||
122 | Opaque, | ||
123 | /// `impl Trait` gets lowered into a type variable. Used for argument | ||
124 | /// position impl Trait when inside the respective function, since it allows | ||
125 | /// us to support that without Chalk. | ||
126 | Param, | ||
127 | /// `impl Trait` gets lowered into a variable that can unify with some | ||
128 | /// type. This is used in places where values flow 'in', i.e. for arguments | ||
129 | /// of functions we're calling, and the return type of the function we're | ||
130 | /// currently checking. | ||
131 | Variable, | ||
132 | /// `impl Trait` is disallowed and will be an error. | ||
133 | Disallowed, | ||
134 | } | ||
135 | |||
136 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
137 | pub enum TypeParamLoweringMode { | ||
138 | Placeholder, | ||
139 | Variable, | ||
140 | } | ||
141 | |||
142 | impl Ty { | ||
143 | pub fn from_hir(ctx: &TyLoweringContext<'_>, type_ref: &TypeRef) -> Self { | ||
144 | Ty::from_hir_ext(ctx, type_ref).0 | ||
145 | } | ||
146 | pub fn from_hir_ext(ctx: &TyLoweringContext<'_>, type_ref: &TypeRef) -> (Self, Option<TypeNs>) { | ||
147 | let mut res = None; | ||
148 | let ty = match type_ref { | ||
149 | TypeRef::Never => Ty::simple(TypeCtor::Never), | ||
150 | TypeRef::Tuple(inner) => { | ||
151 | let inner_tys: Arc<[Ty]> = inner.iter().map(|tr| Ty::from_hir(ctx, tr)).collect(); | ||
152 | Ty::apply( | ||
153 | TypeCtor::Tuple { cardinality: inner_tys.len() as u16 }, | ||
154 | Substs(inner_tys), | ||
155 | ) | ||
156 | } | ||
157 | TypeRef::Path(path) => { | ||
158 | let (ty, res_) = Ty::from_hir_path(ctx, path); | ||
159 | res = res_; | ||
160 | ty | ||
161 | } | ||
162 | TypeRef::RawPtr(inner, mutability) => { | ||
163 | let inner_ty = Ty::from_hir(ctx, inner); | ||
164 | Ty::apply_one(TypeCtor::RawPtr(*mutability), inner_ty) | ||
165 | } | ||
166 | TypeRef::Array(inner) => { | ||
167 | let inner_ty = Ty::from_hir(ctx, inner); | ||
168 | Ty::apply_one(TypeCtor::Array, inner_ty) | ||
169 | } | ||
170 | TypeRef::Slice(inner) => { | ||
171 | let inner_ty = Ty::from_hir(ctx, inner); | ||
172 | Ty::apply_one(TypeCtor::Slice, inner_ty) | ||
173 | } | ||
174 | TypeRef::Reference(inner, mutability) => { | ||
175 | let inner_ty = Ty::from_hir(ctx, inner); | ||
176 | Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) | ||
177 | } | ||
178 | TypeRef::Placeholder => Ty::Unknown, | ||
179 | TypeRef::Fn(params, is_varargs) => { | ||
180 | let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect()); | ||
181 | Ty::apply( | ||
182 | TypeCtor::FnPtr { num_args: sig.len() as u16 - 1, is_varargs: *is_varargs }, | ||
183 | sig, | ||
184 | ) | ||
185 | } | ||
186 | TypeRef::DynTrait(bounds) => { | ||
187 | let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); | ||
188 | let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { | ||
189 | bounds | ||
190 | .iter() | ||
191 | .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) | ||
192 | .collect() | ||
193 | }); | ||
194 | Ty::Dyn(predicates) | ||
195 | } | ||
196 | TypeRef::ImplTrait(bounds) => { | ||
197 | match ctx.impl_trait_mode { | ||
198 | ImplTraitLoweringMode::Opaque => { | ||
199 | let idx = ctx.impl_trait_counter.get(); | ||
200 | ctx.impl_trait_counter.set(idx + 1); | ||
201 | |||
202 | assert!(idx as usize == ctx.opaque_type_data.borrow().len()); | ||
203 | // this dance is to make sure the data is in the right | ||
204 | // place even if we encounter more opaque types while | ||
205 | // lowering the bounds | ||
206 | ctx.opaque_type_data | ||
207 | .borrow_mut() | ||
208 | .push(ReturnTypeImplTrait { bounds: Binders::new(1, Vec::new()) }); | ||
209 | // We don't want to lower the bounds inside the binders | ||
210 | // we're currently in, because they don't end up inside | ||
211 | // those binders. E.g. when we have `impl Trait<impl | ||
212 | // OtherTrait<T>>`, the `impl OtherTrait<T>` can't refer | ||
213 | // to the self parameter from `impl Trait`, and the | ||
214 | // bounds aren't actually stored nested within each | ||
215 | // other, but separately. So if the `T` refers to a type | ||
216 | // parameter of the outer function, it's just one binder | ||
217 | // away instead of two. | ||
218 | let actual_opaque_type_data = ctx | ||
219 | .with_debruijn(DebruijnIndex::INNERMOST, |ctx| { | ||
220 | ReturnTypeImplTrait::from_hir(ctx, &bounds) | ||
221 | }); | ||
222 | ctx.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data; | ||
223 | |||
224 | let func = match ctx.resolver.generic_def() { | ||
225 | Some(GenericDefId::FunctionId(f)) => f, | ||
226 | _ => panic!("opaque impl trait lowering in non-function"), | ||
227 | }; | ||
228 | let impl_trait_id = OpaqueTyId::ReturnTypeImplTrait(func, idx); | ||
229 | let generics = generics(ctx.db.upcast(), func.into()); | ||
230 | let parameters = Substs::bound_vars(&generics, ctx.in_binders); | ||
231 | Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters }) | ||
232 | } | ||
233 | ImplTraitLoweringMode::Param => { | ||
234 | let idx = ctx.impl_trait_counter.get(); | ||
235 | // FIXME we're probably doing something wrong here | ||
236 | ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); | ||
237 | if let Some(def) = ctx.resolver.generic_def() { | ||
238 | let generics = generics(ctx.db.upcast(), def); | ||
239 | let param = generics | ||
240 | .iter() | ||
241 | .filter(|(_, data)| { | ||
242 | data.provenance == TypeParamProvenance::ArgumentImplTrait | ||
243 | }) | ||
244 | .nth(idx as usize) | ||
245 | .map_or(Ty::Unknown, |(id, _)| Ty::Placeholder(id)); | ||
246 | param | ||
247 | } else { | ||
248 | Ty::Unknown | ||
249 | } | ||
250 | } | ||
251 | ImplTraitLoweringMode::Variable => { | ||
252 | let idx = ctx.impl_trait_counter.get(); | ||
253 | // FIXME we're probably doing something wrong here | ||
254 | ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); | ||
255 | let (parent_params, self_params, list_params, _impl_trait_params) = | ||
256 | if let Some(def) = ctx.resolver.generic_def() { | ||
257 | let generics = generics(ctx.db.upcast(), def); | ||
258 | generics.provenance_split() | ||
259 | } else { | ||
260 | (0, 0, 0, 0) | ||
261 | }; | ||
262 | Ty::Bound(BoundVar::new( | ||
263 | ctx.in_binders, | ||
264 | idx as usize + parent_params + self_params + list_params, | ||
265 | )) | ||
266 | } | ||
267 | ImplTraitLoweringMode::Disallowed => { | ||
268 | // FIXME: report error | ||
269 | Ty::Unknown | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | TypeRef::Error => Ty::Unknown, | ||
274 | }; | ||
275 | (ty, res) | ||
276 | } | ||
277 | |||
278 | /// This is only for `generic_predicates_for_param`, where we can't just | ||
279 | /// lower the self types of the predicates since that could lead to cycles. | ||
280 | /// So we just check here if the `type_ref` resolves to a generic param, and which. | ||
281 | fn from_hir_only_param(ctx: &TyLoweringContext<'_>, type_ref: &TypeRef) -> Option<TypeParamId> { | ||
282 | let path = match type_ref { | ||
283 | TypeRef::Path(path) => path, | ||
284 | _ => return None, | ||
285 | }; | ||
286 | if path.type_anchor().is_some() { | ||
287 | return None; | ||
288 | } | ||
289 | if path.segments().len() > 1 { | ||
290 | return None; | ||
291 | } | ||
292 | let resolution = | ||
293 | match ctx.resolver.resolve_path_in_type_ns(ctx.db.upcast(), path.mod_path()) { | ||
294 | Some((it, None)) => it, | ||
295 | _ => return None, | ||
296 | }; | ||
297 | if let TypeNs::GenericParam(param_id) = resolution { | ||
298 | Some(param_id) | ||
299 | } else { | ||
300 | None | ||
301 | } | ||
302 | } | ||
303 | |||
304 | pub(crate) fn from_type_relative_path( | ||
305 | ctx: &TyLoweringContext<'_>, | ||
306 | ty: Ty, | ||
307 | // We need the original resolution to lower `Self::AssocTy` correctly | ||
308 | res: Option<TypeNs>, | ||
309 | remaining_segments: PathSegments<'_>, | ||
310 | ) -> (Ty, Option<TypeNs>) { | ||
311 | if remaining_segments.len() == 1 { | ||
312 | // resolve unselected assoc types | ||
313 | let segment = remaining_segments.first().unwrap(); | ||
314 | (Ty::select_associated_type(ctx, res, segment), None) | ||
315 | } else if remaining_segments.len() > 1 { | ||
316 | // FIXME report error (ambiguous associated type) | ||
317 | (Ty::Unknown, None) | ||
318 | } else { | ||
319 | (ty, res) | ||
320 | } | ||
321 | } | ||
322 | |||
323 | pub(crate) fn from_partly_resolved_hir_path( | ||
324 | ctx: &TyLoweringContext<'_>, | ||
325 | resolution: TypeNs, | ||
326 | resolved_segment: PathSegment<'_>, | ||
327 | remaining_segments: PathSegments<'_>, | ||
328 | infer_args: bool, | ||
329 | ) -> (Ty, Option<TypeNs>) { | ||
330 | let ty = match resolution { | ||
331 | TypeNs::TraitId(trait_) => { | ||
332 | // if this is a bare dyn Trait, we'll directly put the required ^0 for the self type in there | ||
333 | let self_ty = if remaining_segments.len() == 0 { | ||
334 | Some(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0))) | ||
335 | } else { | ||
336 | None | ||
337 | }; | ||
338 | let trait_ref = | ||
339 | TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty); | ||
340 | let ty = if remaining_segments.len() == 1 { | ||
341 | let segment = remaining_segments.first().unwrap(); | ||
342 | let found = associated_type_by_name_including_super_traits( | ||
343 | ctx.db, | ||
344 | trait_ref, | ||
345 | &segment.name, | ||
346 | ); | ||
347 | match found { | ||
348 | Some((super_trait_ref, associated_ty)) => { | ||
349 | // FIXME handle type parameters on the segment | ||
350 | Ty::Projection(ProjectionTy { | ||
351 | associated_ty, | ||
352 | parameters: super_trait_ref.substs, | ||
353 | }) | ||
354 | } | ||
355 | None => { | ||
356 | // FIXME: report error (associated type not found) | ||
357 | Ty::Unknown | ||
358 | } | ||
359 | } | ||
360 | } else if remaining_segments.len() > 1 { | ||
361 | // FIXME report error (ambiguous associated type) | ||
362 | Ty::Unknown | ||
363 | } else { | ||
364 | Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) | ||
365 | }; | ||
366 | return (ty, None); | ||
367 | } | ||
368 | TypeNs::GenericParam(param_id) => { | ||
369 | let generics = generics( | ||
370 | ctx.db.upcast(), | ||
371 | ctx.resolver.generic_def().expect("generics in scope"), | ||
372 | ); | ||
373 | match ctx.type_param_mode { | ||
374 | TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), | ||
375 | TypeParamLoweringMode::Variable => { | ||
376 | let idx = generics.param_idx(param_id).expect("matching generics"); | ||
377 | Ty::Bound(BoundVar::new(ctx.in_binders, idx)) | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | TypeNs::SelfType(impl_id) => { | ||
382 | let generics = generics(ctx.db.upcast(), impl_id.into()); | ||
383 | let substs = match ctx.type_param_mode { | ||
384 | TypeParamLoweringMode::Placeholder => { | ||
385 | Substs::type_params_for_generics(&generics) | ||
386 | } | ||
387 | TypeParamLoweringMode::Variable => { | ||
388 | Substs::bound_vars(&generics, ctx.in_binders) | ||
389 | } | ||
390 | }; | ||
391 | ctx.db.impl_self_ty(impl_id).subst(&substs) | ||
392 | } | ||
393 | TypeNs::AdtSelfType(adt) => { | ||
394 | let generics = generics(ctx.db.upcast(), adt.into()); | ||
395 | let substs = match ctx.type_param_mode { | ||
396 | TypeParamLoweringMode::Placeholder => { | ||
397 | Substs::type_params_for_generics(&generics) | ||
398 | } | ||
399 | TypeParamLoweringMode::Variable => { | ||
400 | Substs::bound_vars(&generics, ctx.in_binders) | ||
401 | } | ||
402 | }; | ||
403 | ctx.db.ty(adt.into()).subst(&substs) | ||
404 | } | ||
405 | |||
406 | TypeNs::AdtId(it) => { | ||
407 | Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) | ||
408 | } | ||
409 | TypeNs::BuiltinType(it) => { | ||
410 | Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) | ||
411 | } | ||
412 | TypeNs::TypeAliasId(it) => { | ||
413 | Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) | ||
414 | } | ||
415 | // FIXME: report error | ||
416 | TypeNs::EnumVariantId(_) => return (Ty::Unknown, None), | ||
417 | }; | ||
418 | |||
419 | Ty::from_type_relative_path(ctx, ty, Some(resolution), remaining_segments) | ||
420 | } | ||
421 | |||
422 | pub(crate) fn from_hir_path(ctx: &TyLoweringContext<'_>, path: &Path) -> (Ty, Option<TypeNs>) { | ||
423 | // Resolve the path (in type namespace) | ||
424 | if let Some(type_ref) = path.type_anchor() { | ||
425 | let (ty, res) = Ty::from_hir_ext(ctx, &type_ref); | ||
426 | return Ty::from_type_relative_path(ctx, ty, res, path.segments()); | ||
427 | } | ||
428 | let (resolution, remaining_index) = | ||
429 | match ctx.resolver.resolve_path_in_type_ns(ctx.db.upcast(), path.mod_path()) { | ||
430 | Some(it) => it, | ||
431 | None => return (Ty::Unknown, None), | ||
432 | }; | ||
433 | let (resolved_segment, remaining_segments) = match remaining_index { | ||
434 | None => ( | ||
435 | path.segments().last().expect("resolved path has at least one element"), | ||
436 | PathSegments::EMPTY, | ||
437 | ), | ||
438 | Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), | ||
439 | }; | ||
440 | Ty::from_partly_resolved_hir_path( | ||
441 | ctx, | ||
442 | resolution, | ||
443 | resolved_segment, | ||
444 | remaining_segments, | ||
445 | false, | ||
446 | ) | ||
447 | } | ||
448 | |||
449 | fn select_associated_type( | ||
450 | ctx: &TyLoweringContext<'_>, | ||
451 | res: Option<TypeNs>, | ||
452 | segment: PathSegment<'_>, | ||
453 | ) -> Ty { | ||
454 | if let Some(res) = res { | ||
455 | let ty = | ||
456 | associated_type_shorthand_candidates(ctx.db, res, move |name, t, associated_ty| { | ||
457 | if name == segment.name { | ||
458 | let substs = match ctx.type_param_mode { | ||
459 | TypeParamLoweringMode::Placeholder => { | ||
460 | // if we're lowering to placeholders, we have to put | ||
461 | // them in now | ||
462 | let s = Substs::type_params( | ||
463 | ctx.db, | ||
464 | ctx.resolver.generic_def().expect( | ||
465 | "there should be generics if there's a generic param", | ||
466 | ), | ||
467 | ); | ||
468 | t.substs.clone().subst_bound_vars(&s) | ||
469 | } | ||
470 | TypeParamLoweringMode::Variable => t.substs.clone(), | ||
471 | }; | ||
472 | // We need to shift in the bound vars, since | ||
473 | // associated_type_shorthand_candidates does not do that | ||
474 | let substs = substs.shift_bound_vars(ctx.in_binders); | ||
475 | // FIXME handle type parameters on the segment | ||
476 | return Some(Ty::Projection(ProjectionTy { | ||
477 | associated_ty, | ||
478 | parameters: substs, | ||
479 | })); | ||
480 | } | ||
481 | |||
482 | None | ||
483 | }); | ||
484 | |||
485 | ty.unwrap_or(Ty::Unknown) | ||
486 | } else { | ||
487 | Ty::Unknown | ||
488 | } | ||
489 | } | ||
490 | |||
491 | fn from_hir_path_inner( | ||
492 | ctx: &TyLoweringContext<'_>, | ||
493 | segment: PathSegment<'_>, | ||
494 | typable: TyDefId, | ||
495 | infer_args: bool, | ||
496 | ) -> Ty { | ||
497 | let generic_def = match typable { | ||
498 | TyDefId::BuiltinType(_) => None, | ||
499 | TyDefId::AdtId(it) => Some(it.into()), | ||
500 | TyDefId::TypeAliasId(it) => Some(it.into()), | ||
501 | }; | ||
502 | let substs = substs_from_path_segment(ctx, segment, generic_def, infer_args); | ||
503 | ctx.db.ty(typable).subst(&substs) | ||
504 | } | ||
505 | |||
506 | /// Collect generic arguments from a path into a `Substs`. See also | ||
507 | /// `create_substs_for_ast_path` and `def_to_ty` in rustc. | ||
508 | pub(super) fn substs_from_path( | ||
509 | ctx: &TyLoweringContext<'_>, | ||
510 | path: &Path, | ||
511 | // Note that we don't call `db.value_type(resolved)` here, | ||
512 | // `ValueTyDefId` is just a convenient way to pass generics and | ||
513 | // special-case enum variants | ||
514 | resolved: ValueTyDefId, | ||
515 | infer_args: bool, | ||
516 | ) -> Substs { | ||
517 | let last = path.segments().last().expect("path should have at least one segment"); | ||
518 | let (segment, generic_def) = match resolved { | ||
519 | ValueTyDefId::FunctionId(it) => (last, Some(it.into())), | ||
520 | ValueTyDefId::StructId(it) => (last, Some(it.into())), | ||
521 | ValueTyDefId::UnionId(it) => (last, Some(it.into())), | ||
522 | ValueTyDefId::ConstId(it) => (last, Some(it.into())), | ||
523 | ValueTyDefId::StaticId(_) => (last, None), | ||
524 | ValueTyDefId::EnumVariantId(var) => { | ||
525 | // the generic args for an enum variant may be either specified | ||
526 | // on the segment referring to the enum, or on the segment | ||
527 | // referring to the variant. So `Option::<T>::None` and | ||
528 | // `Option::None::<T>` are both allowed (though the former is | ||
529 | // preferred). See also `def_ids_for_path_segments` in rustc. | ||
530 | let len = path.segments().len(); | ||
531 | let penultimate = if len >= 2 { path.segments().get(len - 2) } else { None }; | ||
532 | let segment = match penultimate { | ||
533 | Some(segment) if segment.args_and_bindings.is_some() => segment, | ||
534 | _ => last, | ||
535 | }; | ||
536 | (segment, Some(var.parent.into())) | ||
537 | } | ||
538 | }; | ||
539 | substs_from_path_segment(ctx, segment, generic_def, infer_args) | ||
540 | } | ||
541 | } | ||
542 | |||
543 | fn substs_from_path_segment( | ||
544 | ctx: &TyLoweringContext<'_>, | ||
545 | segment: PathSegment<'_>, | ||
546 | def_generic: Option<GenericDefId>, | ||
547 | infer_args: bool, | ||
548 | ) -> Substs { | ||
549 | let mut substs = Vec::new(); | ||
550 | let def_generics = def_generic.map(|def| generics(ctx.db.upcast(), def)); | ||
551 | |||
552 | let (parent_params, self_params, type_params, impl_trait_params) = | ||
553 | def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split()); | ||
554 | let total_len = parent_params + self_params + type_params + impl_trait_params; | ||
555 | |||
556 | substs.extend(iter::repeat(Ty::Unknown).take(parent_params)); | ||
557 | |||
558 | let mut had_explicit_args = false; | ||
559 | |||
560 | if let Some(generic_args) = &segment.args_and_bindings { | ||
561 | if !generic_args.has_self_type { | ||
562 | substs.extend(iter::repeat(Ty::Unknown).take(self_params)); | ||
563 | } | ||
564 | let expected_num = | ||
565 | if generic_args.has_self_type { self_params + type_params } else { type_params }; | ||
566 | let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 }; | ||
567 | // if args are provided, it should be all of them, but we can't rely on that | ||
568 | for arg in generic_args.args.iter().skip(skip).take(expected_num) { | ||
569 | match arg { | ||
570 | GenericArg::Type(type_ref) => { | ||
571 | had_explicit_args = true; | ||
572 | let ty = Ty::from_hir(ctx, type_ref); | ||
573 | substs.push(ty); | ||
574 | } | ||
575 | } | ||
576 | } | ||
577 | } | ||
578 | |||
579 | // handle defaults. In expression or pattern path segments without | ||
580 | // explicitly specified type arguments, missing type arguments are inferred | ||
581 | // (i.e. defaults aren't used). | ||
582 | if !infer_args || had_explicit_args { | ||
583 | if let Some(def_generic) = def_generic { | ||
584 | let defaults = ctx.db.generic_defaults(def_generic); | ||
585 | assert_eq!(total_len, defaults.len()); | ||
586 | |||
587 | for default_ty in defaults.iter().skip(substs.len()) { | ||
588 | // each default can depend on the previous parameters | ||
589 | let substs_so_far = Substs(substs.clone().into()); | ||
590 | substs.push(default_ty.clone().subst(&substs_so_far)); | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | |||
595 | // add placeholders for args that were not provided | ||
596 | // FIXME: emit diagnostics in contexts where this is not allowed | ||
597 | for _ in substs.len()..total_len { | ||
598 | substs.push(Ty::Unknown); | ||
599 | } | ||
600 | assert_eq!(substs.len(), total_len); | ||
601 | |||
602 | Substs(substs.into()) | ||
603 | } | ||
604 | |||
605 | impl TraitRef { | ||
606 | fn from_path( | ||
607 | ctx: &TyLoweringContext<'_>, | ||
608 | path: &Path, | ||
609 | explicit_self_ty: Option<Ty>, | ||
610 | ) -> Option<Self> { | ||
611 | let resolved = | ||
612 | match ctx.resolver.resolve_path_in_type_ns_fully(ctx.db.upcast(), path.mod_path())? { | ||
613 | TypeNs::TraitId(tr) => tr, | ||
614 | _ => return None, | ||
615 | }; | ||
616 | let segment = path.segments().last().expect("path should have at least one segment"); | ||
617 | Some(TraitRef::from_resolved_path(ctx, resolved, segment, explicit_self_ty)) | ||
618 | } | ||
619 | |||
620 | pub(crate) fn from_resolved_path( | ||
621 | ctx: &TyLoweringContext<'_>, | ||
622 | resolved: TraitId, | ||
623 | segment: PathSegment<'_>, | ||
624 | explicit_self_ty: Option<Ty>, | ||
625 | ) -> Self { | ||
626 | let mut substs = TraitRef::substs_from_path(ctx, segment, resolved); | ||
627 | if let Some(self_ty) = explicit_self_ty { | ||
628 | make_mut_slice(&mut substs.0)[0] = self_ty; | ||
629 | } | ||
630 | TraitRef { trait_: resolved, substs } | ||
631 | } | ||
632 | |||
633 | fn from_hir( | ||
634 | ctx: &TyLoweringContext<'_>, | ||
635 | type_ref: &TypeRef, | ||
636 | explicit_self_ty: Option<Ty>, | ||
637 | ) -> Option<Self> { | ||
638 | let path = match type_ref { | ||
639 | TypeRef::Path(path) => path, | ||
640 | _ => return None, | ||
641 | }; | ||
642 | TraitRef::from_path(ctx, path, explicit_self_ty) | ||
643 | } | ||
644 | |||
645 | fn substs_from_path( | ||
646 | ctx: &TyLoweringContext<'_>, | ||
647 | segment: PathSegment<'_>, | ||
648 | resolved: TraitId, | ||
649 | ) -> Substs { | ||
650 | substs_from_path_segment(ctx, segment, Some(resolved.into()), false) | ||
651 | } | ||
652 | |||
653 | pub(crate) fn from_type_bound( | ||
654 | ctx: &TyLoweringContext<'_>, | ||
655 | bound: &TypeBound, | ||
656 | self_ty: Ty, | ||
657 | ) -> Option<TraitRef> { | ||
658 | match bound { | ||
659 | TypeBound::Path(path) => TraitRef::from_path(ctx, path, Some(self_ty)), | ||
660 | TypeBound::Error => None, | ||
661 | } | ||
662 | } | ||
663 | } | ||
664 | |||
665 | impl GenericPredicate { | ||
666 | pub(crate) fn from_where_predicate<'a>( | ||
667 | ctx: &'a TyLoweringContext<'a>, | ||
668 | where_predicate: &'a WherePredicate, | ||
669 | ) -> impl Iterator<Item = GenericPredicate> + 'a { | ||
670 | let self_ty = match &where_predicate.target { | ||
671 | WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref), | ||
672 | WherePredicateTarget::TypeParam(param_id) => { | ||
673 | let generic_def = ctx.resolver.generic_def().expect("generics in scope"); | ||
674 | let generics = generics(ctx.db.upcast(), generic_def); | ||
675 | let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id }; | ||
676 | match ctx.type_param_mode { | ||
677 | TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), | ||
678 | TypeParamLoweringMode::Variable => { | ||
679 | let idx = generics.param_idx(param_id).expect("matching generics"); | ||
680 | Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx)) | ||
681 | } | ||
682 | } | ||
683 | } | ||
684 | }; | ||
685 | GenericPredicate::from_type_bound(ctx, &where_predicate.bound, self_ty) | ||
686 | } | ||
687 | |||
688 | pub(crate) fn from_type_bound<'a>( | ||
689 | ctx: &'a TyLoweringContext<'a>, | ||
690 | bound: &'a TypeBound, | ||
691 | self_ty: Ty, | ||
692 | ) -> impl Iterator<Item = GenericPredicate> + 'a { | ||
693 | let trait_ref = TraitRef::from_type_bound(ctx, bound, self_ty); | ||
694 | iter::once(trait_ref.clone().map_or(GenericPredicate::Error, GenericPredicate::Implemented)) | ||
695 | .chain( | ||
696 | trait_ref | ||
697 | .into_iter() | ||
698 | .flat_map(move |tr| assoc_type_bindings_from_type_bound(ctx, bound, tr)), | ||
699 | ) | ||
700 | } | ||
701 | } | ||
702 | |||
703 | fn assoc_type_bindings_from_type_bound<'a>( | ||
704 | ctx: &'a TyLoweringContext<'a>, | ||
705 | bound: &'a TypeBound, | ||
706 | trait_ref: TraitRef, | ||
707 | ) -> impl Iterator<Item = GenericPredicate> + 'a { | ||
708 | let last_segment = match bound { | ||
709 | TypeBound::Path(path) => path.segments().last(), | ||
710 | TypeBound::Error => None, | ||
711 | }; | ||
712 | last_segment | ||
713 | .into_iter() | ||
714 | .flat_map(|segment| segment.args_and_bindings.into_iter()) | ||
715 | .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) | ||
716 | .flat_map(move |binding| { | ||
717 | let found = associated_type_by_name_including_super_traits( | ||
718 | ctx.db, | ||
719 | trait_ref.clone(), | ||
720 | &binding.name, | ||
721 | ); | ||
722 | let (super_trait_ref, associated_ty) = match found { | ||
723 | None => return SmallVec::<[GenericPredicate; 1]>::new(), | ||
724 | Some(t) => t, | ||
725 | }; | ||
726 | let projection_ty = ProjectionTy { associated_ty, parameters: super_trait_ref.substs }; | ||
727 | let mut preds = SmallVec::with_capacity( | ||
728 | binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), | ||
729 | ); | ||
730 | if let Some(type_ref) = &binding.type_ref { | ||
731 | let ty = Ty::from_hir(ctx, type_ref); | ||
732 | let projection_predicate = | ||
733 | ProjectionPredicate { projection_ty: projection_ty.clone(), ty }; | ||
734 | preds.push(GenericPredicate::Projection(projection_predicate)); | ||
735 | } | ||
736 | for bound in &binding.bounds { | ||
737 | preds.extend(GenericPredicate::from_type_bound( | ||
738 | ctx, | ||
739 | bound, | ||
740 | Ty::Projection(projection_ty.clone()), | ||
741 | )); | ||
742 | } | ||
743 | preds | ||
744 | }) | ||
745 | } | ||
746 | |||
747 | impl ReturnTypeImplTrait { | ||
748 | fn from_hir(ctx: &TyLoweringContext, bounds: &[TypeBound]) -> Self { | ||
749 | mark::hit!(lower_rpit); | ||
750 | let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); | ||
751 | let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { | ||
752 | bounds | ||
753 | .iter() | ||
754 | .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) | ||
755 | .collect() | ||
756 | }); | ||
757 | ReturnTypeImplTrait { bounds: Binders::new(1, predicates) } | ||
758 | } | ||
759 | } | ||
760 | |||
761 | fn count_impl_traits(type_ref: &TypeRef) -> usize { | ||
762 | let mut count = 0; | ||
763 | type_ref.walk(&mut |type_ref| { | ||
764 | if matches!(type_ref, TypeRef::ImplTrait(_)) { | ||
765 | count += 1; | ||
766 | } | ||
767 | }); | ||
768 | count | ||
769 | } | ||
770 | |||
771 | /// Build the signature of a callable item (function, struct or enum variant). | ||
772 | pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig { | ||
773 | match def { | ||
774 | CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), | ||
775 | CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s), | ||
776 | CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), | ||
777 | } | ||
778 | } | ||
779 | |||
780 | pub fn associated_type_shorthand_candidates<R>( | ||
781 | db: &dyn HirDatabase, | ||
782 | res: TypeNs, | ||
783 | mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>, | ||
784 | ) -> Option<R> { | ||
785 | let traits_from_env: Vec<_> = match res { | ||
786 | TypeNs::SelfType(impl_id) => match db.impl_trait(impl_id) { | ||
787 | None => vec![], | ||
788 | Some(trait_ref) => vec![trait_ref.value], | ||
789 | }, | ||
790 | TypeNs::GenericParam(param_id) => { | ||
791 | let predicates = db.generic_predicates_for_param(param_id); | ||
792 | let mut traits_: Vec<_> = predicates | ||
793 | .iter() | ||
794 | .filter_map(|pred| match &pred.value { | ||
795 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | ||
796 | _ => None, | ||
797 | }) | ||
798 | .collect(); | ||
799 | // Handle `Self::Type` referring to own associated type in trait definitions | ||
800 | if let GenericDefId::TraitId(trait_id) = param_id.parent { | ||
801 | let generics = generics(db.upcast(), trait_id.into()); | ||
802 | if generics.params.types[param_id.local_id].provenance | ||
803 | == TypeParamProvenance::TraitSelf | ||
804 | { | ||
805 | let trait_ref = TraitRef { | ||
806 | trait_: trait_id, | ||
807 | substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST), | ||
808 | }; | ||
809 | traits_.push(trait_ref); | ||
810 | } | ||
811 | } | ||
812 | traits_ | ||
813 | } | ||
814 | _ => vec![], | ||
815 | }; | ||
816 | |||
817 | for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) { | ||
818 | let data = db.trait_data(t.trait_); | ||
819 | |||
820 | for (name, assoc_id) in &data.items { | ||
821 | match assoc_id { | ||
822 | AssocItemId::TypeAliasId(alias) => { | ||
823 | if let Some(result) = cb(name, &t, *alias) { | ||
824 | return Some(result); | ||
825 | } | ||
826 | } | ||
827 | AssocItemId::FunctionId(_) | AssocItemId::ConstId(_) => {} | ||
828 | } | ||
829 | } | ||
830 | } | ||
831 | |||
832 | None | ||
833 | } | ||
834 | |||
835 | /// Build the type of all specific fields of a struct or enum variant. | ||
836 | pub(crate) fn field_types_query( | ||
837 | db: &dyn HirDatabase, | ||
838 | variant_id: VariantId, | ||
839 | ) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> { | ||
840 | let var_data = variant_data(db.upcast(), variant_id); | ||
841 | let (resolver, def): (_, GenericDefId) = match variant_id { | ||
842 | VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()), | ||
843 | VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()), | ||
844 | VariantId::EnumVariantId(it) => (it.parent.resolver(db.upcast()), it.parent.into()), | ||
845 | }; | ||
846 | let generics = generics(db.upcast(), def); | ||
847 | let mut res = ArenaMap::default(); | ||
848 | let ctx = | ||
849 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | ||
850 | for (field_id, field_data) in var_data.fields().iter() { | ||
851 | res.insert(field_id, Binders::new(generics.len(), Ty::from_hir(&ctx, &field_data.type_ref))) | ||
852 | } | ||
853 | Arc::new(res) | ||
854 | } | ||
855 | |||
856 | /// This query exists only to be used when resolving short-hand associated types | ||
857 | /// like `T::Item`. | ||
858 | /// | ||
859 | /// See the analogous query in rustc and its comment: | ||
860 | /// https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46 | ||
861 | /// This is a query mostly to handle cycles somewhat gracefully; e.g. the | ||
862 | /// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but | ||
863 | /// these are fine: `T: Foo<U::Item>, U: Foo<()>`. | ||
864 | pub(crate) fn generic_predicates_for_param_query( | ||
865 | db: &dyn HirDatabase, | ||
866 | param_id: TypeParamId, | ||
867 | ) -> Arc<[Binders<GenericPredicate>]> { | ||
868 | let resolver = param_id.parent.resolver(db.upcast()); | ||
869 | let ctx = | ||
870 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | ||
871 | let generics = generics(db.upcast(), param_id.parent); | ||
872 | resolver | ||
873 | .where_predicates_in_scope() | ||
874 | // we have to filter out all other predicates *first*, before attempting to lower them | ||
875 | .filter(|pred| match &pred.target { | ||
876 | WherePredicateTarget::TypeRef(type_ref) => { | ||
877 | Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id) | ||
878 | } | ||
879 | WherePredicateTarget::TypeParam(local_id) => *local_id == param_id.local_id, | ||
880 | }) | ||
881 | .flat_map(|pred| { | ||
882 | GenericPredicate::from_where_predicate(&ctx, pred) | ||
883 | .map(|p| Binders::new(generics.len(), p)) | ||
884 | }) | ||
885 | .collect() | ||
886 | } | ||
887 | |||
888 | pub(crate) fn generic_predicates_for_param_recover( | ||
889 | _db: &dyn HirDatabase, | ||
890 | _cycle: &[String], | ||
891 | _param_id: &TypeParamId, | ||
892 | ) -> Arc<[Binders<GenericPredicate>]> { | ||
893 | Arc::new([]) | ||
894 | } | ||
895 | |||
896 | impl TraitEnvironment { | ||
897 | pub fn lower(db: &dyn HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> { | ||
898 | let ctx = TyLoweringContext::new(db, &resolver) | ||
899 | .with_type_param_mode(TypeParamLoweringMode::Placeholder); | ||
900 | let mut predicates = resolver | ||
901 | .where_predicates_in_scope() | ||
902 | .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) | ||
903 | .collect::<Vec<_>>(); | ||
904 | |||
905 | if let Some(def) = resolver.generic_def() { | ||
906 | let container: Option<AssocContainerId> = match def { | ||
907 | // FIXME: is there a function for this? | ||
908 | GenericDefId::FunctionId(f) => Some(f.lookup(db.upcast()).container), | ||
909 | GenericDefId::AdtId(_) => None, | ||
910 | GenericDefId::TraitId(_) => None, | ||
911 | GenericDefId::TypeAliasId(t) => Some(t.lookup(db.upcast()).container), | ||
912 | GenericDefId::ImplId(_) => None, | ||
913 | GenericDefId::EnumVariantId(_) => None, | ||
914 | GenericDefId::ConstId(c) => Some(c.lookup(db.upcast()).container), | ||
915 | }; | ||
916 | if let Some(AssocContainerId::TraitId(trait_id)) = container { | ||
917 | // add `Self: Trait<T1, T2, ...>` to the environment in trait | ||
918 | // function default implementations (and hypothetical code | ||
919 | // inside consts or type aliases) | ||
920 | test_utils::mark::hit!(trait_self_implements_self); | ||
921 | let substs = Substs::type_params(db, trait_id); | ||
922 | let trait_ref = TraitRef { trait_: trait_id, substs }; | ||
923 | let pred = GenericPredicate::Implemented(trait_ref); | ||
924 | |||
925 | predicates.push(pred); | ||
926 | } | ||
927 | } | ||
928 | |||
929 | Arc::new(TraitEnvironment { predicates }) | ||
930 | } | ||
931 | } | ||
932 | |||
933 | /// Resolve the where clause(s) of an item with generics. | ||
934 | pub(crate) fn generic_predicates_query( | ||
935 | db: &dyn HirDatabase, | ||
936 | def: GenericDefId, | ||
937 | ) -> Arc<[Binders<GenericPredicate>]> { | ||
938 | let resolver = def.resolver(db.upcast()); | ||
939 | let ctx = | ||
940 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | ||
941 | let generics = generics(db.upcast(), def); | ||
942 | resolver | ||
943 | .where_predicates_in_scope() | ||
944 | .flat_map(|pred| { | ||
945 | GenericPredicate::from_where_predicate(&ctx, pred) | ||
946 | .map(|p| Binders::new(generics.len(), p)) | ||
947 | }) | ||
948 | .collect() | ||
949 | } | ||
950 | |||
951 | /// Resolve the default type params from generics | ||
952 | pub(crate) fn generic_defaults_query( | ||
953 | db: &dyn HirDatabase, | ||
954 | def: GenericDefId, | ||
955 | ) -> Arc<[Binders<Ty>]> { | ||
956 | let resolver = def.resolver(db.upcast()); | ||
957 | let ctx = | ||
958 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | ||
959 | let generic_params = generics(db.upcast(), def); | ||
960 | |||
961 | let defaults = generic_params | ||
962 | .iter() | ||
963 | .enumerate() | ||
964 | .map(|(idx, (_, p))| { | ||
965 | let mut ty = p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(&ctx, t)); | ||
966 | |||
967 | // Each default can only refer to previous parameters. | ||
968 | ty.walk_mut_binders( | ||
969 | &mut |ty, binders| match ty { | ||
970 | Ty::Bound(BoundVar { debruijn, index }) if *debruijn == binders => { | ||
971 | if *index >= idx { | ||
972 | // type variable default referring to parameter coming | ||
973 | // after it. This is forbidden (FIXME: report | ||
974 | // diagnostic) | ||
975 | *ty = Ty::Unknown; | ||
976 | } | ||
977 | } | ||
978 | _ => {} | ||
979 | }, | ||
980 | DebruijnIndex::INNERMOST, | ||
981 | ); | ||
982 | |||
983 | Binders::new(idx, ty) | ||
984 | }) | ||
985 | .collect(); | ||
986 | |||
987 | defaults | ||
988 | } | ||
989 | |||
990 | fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { | ||
991 | let data = db.function_data(def); | ||
992 | let resolver = def.resolver(db.upcast()); | ||
993 | let ctx_params = TyLoweringContext::new(db, &resolver) | ||
994 | .with_impl_trait_mode(ImplTraitLoweringMode::Variable) | ||
995 | .with_type_param_mode(TypeParamLoweringMode::Variable); | ||
996 | let params = data.params.iter().map(|tr| Ty::from_hir(&ctx_params, tr)).collect::<Vec<_>>(); | ||
997 | let ctx_ret = TyLoweringContext::new(db, &resolver) | ||
998 | .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) | ||
999 | .with_type_param_mode(TypeParamLoweringMode::Variable); | ||
1000 | let ret = Ty::from_hir(&ctx_ret, &data.ret_type); | ||
1001 | let generics = generics(db.upcast(), def.into()); | ||
1002 | let num_binders = generics.len(); | ||
1003 | Binders::new(num_binders, FnSig::from_params_and_return(params, ret, data.is_varargs)) | ||
1004 | } | ||
1005 | |||
1006 | /// Build the declared type of a function. This should not need to look at the | ||
1007 | /// function body. | ||
1008 | fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> { | ||
1009 | let generics = generics(db.upcast(), def.into()); | ||
1010 | let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST); | ||
1011 | Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs)) | ||
1012 | } | ||
1013 | |||
1014 | /// Build the declared type of a const. | ||
1015 | fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> { | ||
1016 | let data = db.const_data(def); | ||
1017 | let generics = generics(db.upcast(), def.into()); | ||
1018 | let resolver = def.resolver(db.upcast()); | ||
1019 | let ctx = | ||
1020 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | ||
1021 | |||
1022 | Binders::new(generics.len(), Ty::from_hir(&ctx, &data.type_ref)) | ||
1023 | } | ||
1024 | |||
1025 | /// Build the declared type of a static. | ||
1026 | fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> { | ||
1027 | let data = db.static_data(def); | ||
1028 | let resolver = def.resolver(db.upcast()); | ||
1029 | let ctx = TyLoweringContext::new(db, &resolver); | ||
1030 | |||
1031 | Binders::new(0, Ty::from_hir(&ctx, &data.type_ref)) | ||
1032 | } | ||
1033 | |||
1034 | /// Build the declared type of a static. | ||
1035 | fn type_for_builtin(def: BuiltinType) -> Ty { | ||
1036 | Ty::simple(match def { | ||
1037 | BuiltinType::Char => TypeCtor::Char, | ||
1038 | BuiltinType::Bool => TypeCtor::Bool, | ||
1039 | BuiltinType::Str => TypeCtor::Str, | ||
1040 | BuiltinType::Int(t) => TypeCtor::Int(IntTy::from(t).into()), | ||
1041 | BuiltinType::Float(t) => TypeCtor::Float(FloatTy::from(t).into()), | ||
1042 | }) | ||
1043 | } | ||
1044 | |||
1045 | fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig { | ||
1046 | let struct_data = db.struct_data(def); | ||
1047 | let fields = struct_data.variant_data.fields(); | ||
1048 | let resolver = def.resolver(db.upcast()); | ||
1049 | let ctx = | ||
1050 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | ||
1051 | let params = | ||
1052 | fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); | ||
1053 | let ret = type_for_adt(db, def.into()); | ||
1054 | Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false)) | ||
1055 | } | ||
1056 | |||
1057 | /// Build the type of a tuple struct constructor. | ||
1058 | fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<Ty> { | ||
1059 | let struct_data = db.struct_data(def); | ||
1060 | if let StructKind::Unit = struct_data.variant_data.kind() { | ||
1061 | return type_for_adt(db, def.into()); | ||
1062 | } | ||
1063 | let generics = generics(db.upcast(), def.into()); | ||
1064 | let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST); | ||
1065 | Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs)) | ||
1066 | } | ||
1067 | |||
1068 | fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig { | ||
1069 | let enum_data = db.enum_data(def.parent); | ||
1070 | let var_data = &enum_data.variants[def.local_id]; | ||
1071 | let fields = var_data.variant_data.fields(); | ||
1072 | let resolver = def.parent.resolver(db.upcast()); | ||
1073 | let ctx = | ||
1074 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | ||
1075 | let params = | ||
1076 | fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); | ||
1077 | let ret = type_for_adt(db, def.parent.into()); | ||
1078 | Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false)) | ||
1079 | } | ||
1080 | |||
1081 | /// Build the type of a tuple enum variant constructor. | ||
1082 | fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> Binders<Ty> { | ||
1083 | let enum_data = db.enum_data(def.parent); | ||
1084 | let var_data = &enum_data.variants[def.local_id].variant_data; | ||
1085 | if let StructKind::Unit = var_data.kind() { | ||
1086 | return type_for_adt(db, def.parent.into()); | ||
1087 | } | ||
1088 | let generics = generics(db.upcast(), def.parent.into()); | ||
1089 | let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST); | ||
1090 | Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs)) | ||
1091 | } | ||
1092 | |||
1093 | fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { | ||
1094 | let generics = generics(db.upcast(), adt.into()); | ||
1095 | let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST); | ||
1096 | Binders::new(substs.len(), Ty::apply(TypeCtor::Adt(adt), substs)) | ||
1097 | } | ||
1098 | |||
1099 | fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { | ||
1100 | let generics = generics(db.upcast(), t.into()); | ||
1101 | let resolver = t.resolver(db.upcast()); | ||
1102 | let ctx = | ||
1103 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | ||
1104 | let type_ref = &db.type_alias_data(t).type_ref; | ||
1105 | let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST); | ||
1106 | let inner = Ty::from_hir(&ctx, type_ref.as_ref().unwrap_or(&TypeRef::Error)); | ||
1107 | Binders::new(substs.len(), inner) | ||
1108 | } | ||
1109 | |||
1110 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1111 | pub enum CallableDefId { | ||
1112 | FunctionId(FunctionId), | ||
1113 | StructId(StructId), | ||
1114 | EnumVariantId(EnumVariantId), | ||
1115 | } | ||
1116 | impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId); | ||
1117 | |||
1118 | impl CallableDefId { | ||
1119 | pub fn krate(self, db: &dyn HirDatabase) -> CrateId { | ||
1120 | let db = db.upcast(); | ||
1121 | match self { | ||
1122 | CallableDefId::FunctionId(f) => f.lookup(db).module(db), | ||
1123 | CallableDefId::StructId(s) => s.lookup(db).container.module(db), | ||
1124 | CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container.module(db), | ||
1125 | } | ||
1126 | .krate | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1130 | impl From<CallableDefId> for GenericDefId { | ||
1131 | fn from(def: CallableDefId) -> GenericDefId { | ||
1132 | match def { | ||
1133 | CallableDefId::FunctionId(f) => f.into(), | ||
1134 | CallableDefId::StructId(s) => s.into(), | ||
1135 | CallableDefId::EnumVariantId(e) => e.into(), | ||
1136 | } | ||
1137 | } | ||
1138 | } | ||
1139 | |||
1140 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1141 | pub enum TyDefId { | ||
1142 | BuiltinType(BuiltinType), | ||
1143 | AdtId(AdtId), | ||
1144 | TypeAliasId(TypeAliasId), | ||
1145 | } | ||
1146 | impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId); | ||
1147 | |||
1148 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1149 | pub enum ValueTyDefId { | ||
1150 | FunctionId(FunctionId), | ||
1151 | StructId(StructId), | ||
1152 | UnionId(UnionId), | ||
1153 | EnumVariantId(EnumVariantId), | ||
1154 | ConstId(ConstId), | ||
1155 | StaticId(StaticId), | ||
1156 | } | ||
1157 | impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId); | ||
1158 | |||
1159 | /// Build the declared type of an item. This depends on the namespace; e.g. for | ||
1160 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and | ||
1161 | /// the constructor function `(usize) -> Foo` which lives in the values | ||
1162 | /// namespace. | ||
1163 | pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> { | ||
1164 | match def { | ||
1165 | TyDefId::BuiltinType(it) => Binders::new(0, type_for_builtin(it)), | ||
1166 | TyDefId::AdtId(it) => type_for_adt(db, it), | ||
1167 | TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), | ||
1168 | } | ||
1169 | } | ||
1170 | |||
1171 | pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &[String], def: &TyDefId) -> Binders<Ty> { | ||
1172 | let num_binders = match *def { | ||
1173 | TyDefId::BuiltinType(_) => 0, | ||
1174 | TyDefId::AdtId(it) => generics(db.upcast(), it.into()).len(), | ||
1175 | TyDefId::TypeAliasId(it) => generics(db.upcast(), it.into()).len(), | ||
1176 | }; | ||
1177 | Binders::new(num_binders, Ty::Unknown) | ||
1178 | } | ||
1179 | |||
1180 | pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders<Ty> { | ||
1181 | match def { | ||
1182 | ValueTyDefId::FunctionId(it) => type_for_fn(db, it), | ||
1183 | ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), | ||
1184 | ValueTyDefId::UnionId(it) => type_for_adt(db, it.into()), | ||
1185 | ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), | ||
1186 | ValueTyDefId::ConstId(it) => type_for_const(db, it), | ||
1187 | ValueTyDefId::StaticId(it) => type_for_static(db, it), | ||
1188 | } | ||
1189 | } | ||
1190 | |||
1191 | pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> { | ||
1192 | let impl_data = db.impl_data(impl_id); | ||
1193 | let resolver = impl_id.resolver(db.upcast()); | ||
1194 | let generics = generics(db.upcast(), impl_id.into()); | ||
1195 | let ctx = | ||
1196 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | ||
1197 | Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type)) | ||
1198 | } | ||
1199 | |||
1200 | pub(crate) fn impl_self_ty_recover( | ||
1201 | db: &dyn HirDatabase, | ||
1202 | _cycle: &[String], | ||
1203 | impl_id: &ImplId, | ||
1204 | ) -> Binders<Ty> { | ||
1205 | let generics = generics(db.upcast(), (*impl_id).into()); | ||
1206 | Binders::new(generics.len(), Ty::Unknown) | ||
1207 | } | ||
1208 | |||
1209 | pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> { | ||
1210 | let impl_data = db.impl_data(impl_id); | ||
1211 | let resolver = impl_id.resolver(db.upcast()); | ||
1212 | let ctx = | ||
1213 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | ||
1214 | let self_ty = db.impl_self_ty(impl_id); | ||
1215 | let target_trait = impl_data.target_trait.as_ref()?; | ||
1216 | Some(Binders::new( | ||
1217 | self_ty.num_binders, | ||
1218 | TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value))?, | ||
1219 | )) | ||
1220 | } | ||
1221 | |||
1222 | pub(crate) fn return_type_impl_traits( | ||
1223 | db: &dyn HirDatabase, | ||
1224 | def: hir_def::FunctionId, | ||
1225 | ) -> Option<Arc<Binders<ReturnTypeImplTraits>>> { | ||
1226 | // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe | ||
1227 | let data = db.function_data(def); | ||
1228 | let resolver = def.resolver(db.upcast()); | ||
1229 | let ctx_ret = TyLoweringContext::new(db, &resolver) | ||
1230 | .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) | ||
1231 | .with_type_param_mode(TypeParamLoweringMode::Variable); | ||
1232 | let _ret = Ty::from_hir(&ctx_ret, &data.ret_type); | ||
1233 | let generics = generics(db.upcast(), def.into()); | ||
1234 | let num_binders = generics.len(); | ||
1235 | let return_type_impl_traits = | ||
1236 | ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() }; | ||
1237 | if return_type_impl_traits.impl_traits.is_empty() { | ||
1238 | None | ||
1239 | } else { | ||
1240 | Some(Arc::new(Binders::new(num_binders, return_type_impl_traits))) | ||
1241 | } | ||
1242 | } | ||
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs new file mode 100644 index 000000000..ec59145c7 --- /dev/null +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -0,0 +1,769 @@ | |||
1 | //! This module is concerned with finding methods that a given type provides. | ||
2 | //! For details about how this works in rustc, see the method lookup page in the | ||
3 | //! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html) | ||
4 | //! and the corresponding code mostly in librustc_typeck/check/method/probe.rs. | ||
5 | use std::{iter, sync::Arc}; | ||
6 | |||
7 | use arrayvec::ArrayVec; | ||
8 | use base_db::CrateId; | ||
9 | use hir_def::{ | ||
10 | builtin_type::{IntBitness, Signedness}, | ||
11 | lang_item::LangItemTarget, | ||
12 | type_ref::Mutability, | ||
13 | AssocContainerId, AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId, | ||
14 | }; | ||
15 | use hir_expand::name::Name; | ||
16 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
17 | |||
18 | use super::Substs; | ||
19 | use crate::{ | ||
20 | autoderef, | ||
21 | db::HirDatabase, | ||
22 | primitive::{FloatBitness, FloatTy, IntTy}, | ||
23 | utils::all_super_traits, | ||
24 | ApplicationTy, Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind, | ||
25 | TypeCtor, TypeWalk, | ||
26 | }; | ||
27 | |||
28 | /// This is used as a key for indexing impls. | ||
29 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
30 | pub enum TyFingerprint { | ||
31 | Apply(TypeCtor), | ||
32 | } | ||
33 | |||
34 | impl TyFingerprint { | ||
35 | /// Creates a TyFingerprint for looking up an impl. Only certain types can | ||
36 | /// have impls: if we have some `struct S`, we can have an `impl S`, but not | ||
37 | /// `impl &S`. Hence, this will return `None` for reference types and such. | ||
38 | pub(crate) fn for_impl(ty: &Ty) -> Option<TyFingerprint> { | ||
39 | match ty { | ||
40 | Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)), | ||
41 | _ => None, | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | |||
46 | pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ | ||
47 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
48 | signedness: Signedness::Unsigned, | ||
49 | bitness: IntBitness::X8, | ||
50 | })), | ||
51 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
52 | signedness: Signedness::Unsigned, | ||
53 | bitness: IntBitness::X16, | ||
54 | })), | ||
55 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
56 | signedness: Signedness::Unsigned, | ||
57 | bitness: IntBitness::X32, | ||
58 | })), | ||
59 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
60 | signedness: Signedness::Unsigned, | ||
61 | bitness: IntBitness::X64, | ||
62 | })), | ||
63 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
64 | signedness: Signedness::Unsigned, | ||
65 | bitness: IntBitness::X128, | ||
66 | })), | ||
67 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
68 | signedness: Signedness::Unsigned, | ||
69 | bitness: IntBitness::Xsize, | ||
70 | })), | ||
71 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
72 | signedness: Signedness::Signed, | ||
73 | bitness: IntBitness::X8, | ||
74 | })), | ||
75 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
76 | signedness: Signedness::Signed, | ||
77 | bitness: IntBitness::X16, | ||
78 | })), | ||
79 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
80 | signedness: Signedness::Signed, | ||
81 | bitness: IntBitness::X32, | ||
82 | })), | ||
83 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
84 | signedness: Signedness::Signed, | ||
85 | bitness: IntBitness::X64, | ||
86 | })), | ||
87 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
88 | signedness: Signedness::Signed, | ||
89 | bitness: IntBitness::X128, | ||
90 | })), | ||
91 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
92 | signedness: Signedness::Signed, | ||
93 | bitness: IntBitness::Xsize, | ||
94 | })), | ||
95 | ]; | ||
96 | |||
97 | pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [ | ||
98 | TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 })), | ||
99 | TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 })), | ||
100 | ]; | ||
101 | |||
102 | /// Trait impls defined or available in some crate. | ||
103 | #[derive(Debug, Eq, PartialEq)] | ||
104 | pub struct TraitImpls { | ||
105 | // If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type. | ||
106 | map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, | ||
107 | } | ||
108 | |||
109 | impl TraitImpls { | ||
110 | pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { | ||
111 | let _p = profile::span("trait_impls_in_crate_query"); | ||
112 | let mut impls = Self { map: FxHashMap::default() }; | ||
113 | |||
114 | let crate_def_map = db.crate_def_map(krate); | ||
115 | for (_module_id, module_data) in crate_def_map.modules.iter() { | ||
116 | for impl_id in module_data.scope.impls() { | ||
117 | let target_trait = match db.impl_trait(impl_id) { | ||
118 | Some(tr) => tr.value.trait_, | ||
119 | None => continue, | ||
120 | }; | ||
121 | let self_ty = db.impl_self_ty(impl_id); | ||
122 | let self_ty_fp = TyFingerprint::for_impl(&self_ty.value); | ||
123 | impls | ||
124 | .map | ||
125 | .entry(target_trait) | ||
126 | .or_default() | ||
127 | .entry(self_ty_fp) | ||
128 | .or_default() | ||
129 | .push(impl_id); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | Arc::new(impls) | ||
134 | } | ||
135 | |||
136 | pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { | ||
137 | let _p = profile::span("trait_impls_in_deps_query"); | ||
138 | let crate_graph = db.crate_graph(); | ||
139 | let mut res = Self { map: FxHashMap::default() }; | ||
140 | |||
141 | for krate in crate_graph.transitive_deps(krate) { | ||
142 | res.merge(&db.trait_impls_in_crate(krate)); | ||
143 | } | ||
144 | |||
145 | Arc::new(res) | ||
146 | } | ||
147 | |||
148 | fn merge(&mut self, other: &Self) { | ||
149 | for (trait_, other_map) in &other.map { | ||
150 | let map = self.map.entry(*trait_).or_default(); | ||
151 | for (fp, impls) in other_map { | ||
152 | let vec = map.entry(*fp).or_default(); | ||
153 | vec.extend(impls); | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /// Queries all impls of the given trait. | ||
159 | pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ { | ||
160 | self.map | ||
161 | .get(&trait_) | ||
162 | .into_iter() | ||
163 | .flat_map(|map| map.values().flat_map(|v| v.iter().copied())) | ||
164 | } | ||
165 | |||
166 | /// Queries all impls of `trait_` that may apply to `self_ty`. | ||
167 | pub fn for_trait_and_self_ty( | ||
168 | &self, | ||
169 | trait_: TraitId, | ||
170 | self_ty: TyFingerprint, | ||
171 | ) -> impl Iterator<Item = ImplId> + '_ { | ||
172 | self.map | ||
173 | .get(&trait_) | ||
174 | .into_iter() | ||
175 | .flat_map(move |map| map.get(&None).into_iter().chain(map.get(&Some(self_ty)))) | ||
176 | .flat_map(|v| v.iter().copied()) | ||
177 | } | ||
178 | |||
179 | pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ { | ||
180 | self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied())) | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /// Inherent impls defined in some crate. | ||
185 | /// | ||
186 | /// Inherent impls can only be defined in the crate that also defines the self type of the impl | ||
187 | /// (note that some primitives are considered to be defined by both libcore and liballoc). | ||
188 | /// | ||
189 | /// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a | ||
190 | /// single crate. | ||
191 | #[derive(Debug, Eq, PartialEq)] | ||
192 | pub struct InherentImpls { | ||
193 | map: FxHashMap<TyFingerprint, Vec<ImplId>>, | ||
194 | } | ||
195 | |||
196 | impl InherentImpls { | ||
197 | pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { | ||
198 | let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default(); | ||
199 | |||
200 | let crate_def_map = db.crate_def_map(krate); | ||
201 | for (_module_id, module_data) in crate_def_map.modules.iter() { | ||
202 | for impl_id in module_data.scope.impls() { | ||
203 | let data = db.impl_data(impl_id); | ||
204 | if data.target_trait.is_some() { | ||
205 | continue; | ||
206 | } | ||
207 | |||
208 | let self_ty = db.impl_self_ty(impl_id); | ||
209 | if let Some(fp) = TyFingerprint::for_impl(&self_ty.value) { | ||
210 | map.entry(fp).or_default().push(impl_id); | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
215 | Arc::new(Self { map }) | ||
216 | } | ||
217 | |||
218 | pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { | ||
219 | match TyFingerprint::for_impl(self_ty) { | ||
220 | Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]), | ||
221 | None => &[], | ||
222 | } | ||
223 | } | ||
224 | |||
225 | pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ { | ||
226 | self.map.values().flat_map(|v| v.iter().copied()) | ||
227 | } | ||
228 | } | ||
229 | |||
230 | impl Ty { | ||
231 | pub fn def_crates( | ||
232 | &self, | ||
233 | db: &dyn HirDatabase, | ||
234 | cur_crate: CrateId, | ||
235 | ) -> Option<ArrayVec<[CrateId; 2]>> { | ||
236 | // Types like slice can have inherent impls in several crates, (core and alloc). | ||
237 | // The corresponding impls are marked with lang items, so we can use them to find the required crates. | ||
238 | macro_rules! lang_item_crate { | ||
239 | ($($name:expr),+ $(,)?) => {{ | ||
240 | let mut v = ArrayVec::<[LangItemTarget; 2]>::new(); | ||
241 | $( | ||
242 | v.extend(db.lang_item(cur_crate, $name.into())); | ||
243 | )+ | ||
244 | v | ||
245 | }}; | ||
246 | } | ||
247 | |||
248 | let lang_item_targets = match self { | ||
249 | Ty::Apply(a_ty) => match a_ty.ctor { | ||
250 | TypeCtor::Adt(def_id) => { | ||
251 | return Some(std::iter::once(def_id.module(db.upcast()).krate).collect()) | ||
252 | } | ||
253 | TypeCtor::Bool => lang_item_crate!("bool"), | ||
254 | TypeCtor::Char => lang_item_crate!("char"), | ||
255 | TypeCtor::Float(f) => match f.bitness { | ||
256 | // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) | ||
257 | FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"), | ||
258 | FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"), | ||
259 | }, | ||
260 | TypeCtor::Int(i) => lang_item_crate!(i.ty_to_string()), | ||
261 | TypeCtor::Str => lang_item_crate!("str_alloc", "str"), | ||
262 | TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"), | ||
263 | TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"), | ||
264 | TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!("mut_ptr"), | ||
265 | _ => return None, | ||
266 | }, | ||
267 | _ => return None, | ||
268 | }; | ||
269 | let res = lang_item_targets | ||
270 | .into_iter() | ||
271 | .filter_map(|it| match it { | ||
272 | LangItemTarget::ImplDefId(it) => Some(it), | ||
273 | _ => None, | ||
274 | }) | ||
275 | .map(|it| it.lookup(db.upcast()).container.module(db.upcast()).krate) | ||
276 | .collect(); | ||
277 | Some(res) | ||
278 | } | ||
279 | } | ||
280 | /// Look up the method with the given name, returning the actual autoderefed | ||
281 | /// receiver type (but without autoref applied yet). | ||
282 | pub(crate) fn lookup_method( | ||
283 | ty: &Canonical<Ty>, | ||
284 | db: &dyn HirDatabase, | ||
285 | env: Arc<TraitEnvironment>, | ||
286 | krate: CrateId, | ||
287 | traits_in_scope: &FxHashSet<TraitId>, | ||
288 | name: &Name, | ||
289 | ) -> Option<(Ty, FunctionId)> { | ||
290 | iterate_method_candidates( | ||
291 | ty, | ||
292 | db, | ||
293 | env, | ||
294 | krate, | ||
295 | &traits_in_scope, | ||
296 | Some(name), | ||
297 | LookupMode::MethodCall, | ||
298 | |ty, f| match f { | ||
299 | AssocItemId::FunctionId(f) => Some((ty.clone(), f)), | ||
300 | _ => None, | ||
301 | }, | ||
302 | ) | ||
303 | } | ||
304 | |||
305 | /// Whether we're looking up a dotted method call (like `v.len()`) or a path | ||
306 | /// (like `Vec::new`). | ||
307 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
308 | pub enum LookupMode { | ||
309 | /// Looking up a method call like `v.len()`: We only consider candidates | ||
310 | /// that have a `self` parameter, and do autoderef. | ||
311 | MethodCall, | ||
312 | /// Looking up a path like `Vec::new` or `Vec::default`: We consider all | ||
313 | /// candidates including associated constants, but don't do autoderef. | ||
314 | Path, | ||
315 | } | ||
316 | |||
317 | // This would be nicer if it just returned an iterator, but that runs into | ||
318 | // lifetime problems, because we need to borrow temp `CrateImplDefs`. | ||
319 | // FIXME add a context type here? | ||
320 | pub fn iterate_method_candidates<T>( | ||
321 | ty: &Canonical<Ty>, | ||
322 | db: &dyn HirDatabase, | ||
323 | env: Arc<TraitEnvironment>, | ||
324 | krate: CrateId, | ||
325 | traits_in_scope: &FxHashSet<TraitId>, | ||
326 | name: Option<&Name>, | ||
327 | mode: LookupMode, | ||
328 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | ||
329 | ) -> Option<T> { | ||
330 | let mut slot = None; | ||
331 | iterate_method_candidates_impl( | ||
332 | ty, | ||
333 | db, | ||
334 | env, | ||
335 | krate, | ||
336 | traits_in_scope, | ||
337 | name, | ||
338 | mode, | ||
339 | &mut |ty, item| { | ||
340 | assert!(slot.is_none()); | ||
341 | slot = callback(ty, item); | ||
342 | slot.is_some() | ||
343 | }, | ||
344 | ); | ||
345 | slot | ||
346 | } | ||
347 | |||
348 | fn iterate_method_candidates_impl( | ||
349 | ty: &Canonical<Ty>, | ||
350 | db: &dyn HirDatabase, | ||
351 | env: Arc<TraitEnvironment>, | ||
352 | krate: CrateId, | ||
353 | traits_in_scope: &FxHashSet<TraitId>, | ||
354 | name: Option<&Name>, | ||
355 | mode: LookupMode, | ||
356 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
357 | ) -> bool { | ||
358 | match mode { | ||
359 | LookupMode::MethodCall => { | ||
360 | // For method calls, rust first does any number of autoderef, and then one | ||
361 | // autoref (i.e. when the method takes &self or &mut self). We just ignore | ||
362 | // the autoref currently -- when we find a method matching the given name, | ||
363 | // we assume it fits. | ||
364 | |||
365 | // Also note that when we've got a receiver like &S, even if the method we | ||
366 | // find in the end takes &self, we still do the autoderef step (just as | ||
367 | // rustc does an autoderef and then autoref again). | ||
368 | let ty = InEnvironment { value: ty.clone(), environment: env.clone() }; | ||
369 | |||
370 | // We have to be careful about the order we're looking at candidates | ||
371 | // in here. Consider the case where we're resolving `x.clone()` | ||
372 | // where `x: &Vec<_>`. This resolves to the clone method with self | ||
373 | // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where | ||
374 | // the receiver type exactly matches before cases where we have to | ||
375 | // do autoref. But in the autoderef steps, the `&_` self type comes | ||
376 | // up *before* the `Vec<_>` self type. | ||
377 | // | ||
378 | // On the other hand, we don't want to just pick any by-value method | ||
379 | // before any by-autoref method; it's just that we need to consider | ||
380 | // the methods by autoderef order of *receiver types*, not *self | ||
381 | // types*. | ||
382 | |||
383 | let deref_chain = autoderef_method_receiver(db, krate, ty); | ||
384 | for i in 0..deref_chain.len() { | ||
385 | if iterate_method_candidates_with_autoref( | ||
386 | &deref_chain[i..], | ||
387 | db, | ||
388 | env.clone(), | ||
389 | krate, | ||
390 | traits_in_scope, | ||
391 | name, | ||
392 | callback, | ||
393 | ) { | ||
394 | return true; | ||
395 | } | ||
396 | } | ||
397 | false | ||
398 | } | ||
399 | LookupMode::Path => { | ||
400 | // No autoderef for path lookups | ||
401 | iterate_method_candidates_for_self_ty( | ||
402 | &ty, | ||
403 | db, | ||
404 | env, | ||
405 | krate, | ||
406 | traits_in_scope, | ||
407 | name, | ||
408 | callback, | ||
409 | ) | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | fn iterate_method_candidates_with_autoref( | ||
415 | deref_chain: &[Canonical<Ty>], | ||
416 | db: &dyn HirDatabase, | ||
417 | env: Arc<TraitEnvironment>, | ||
418 | krate: CrateId, | ||
419 | traits_in_scope: &FxHashSet<TraitId>, | ||
420 | name: Option<&Name>, | ||
421 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
422 | ) -> bool { | ||
423 | if iterate_method_candidates_by_receiver( | ||
424 | &deref_chain[0], | ||
425 | &deref_chain[1..], | ||
426 | db, | ||
427 | env.clone(), | ||
428 | krate, | ||
429 | &traits_in_scope, | ||
430 | name, | ||
431 | &mut callback, | ||
432 | ) { | ||
433 | return true; | ||
434 | } | ||
435 | let refed = Canonical { | ||
436 | kinds: deref_chain[0].kinds.clone(), | ||
437 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), | ||
438 | }; | ||
439 | if iterate_method_candidates_by_receiver( | ||
440 | &refed, | ||
441 | deref_chain, | ||
442 | db, | ||
443 | env.clone(), | ||
444 | krate, | ||
445 | &traits_in_scope, | ||
446 | name, | ||
447 | &mut callback, | ||
448 | ) { | ||
449 | return true; | ||
450 | } | ||
451 | let ref_muted = Canonical { | ||
452 | kinds: deref_chain[0].kinds.clone(), | ||
453 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), | ||
454 | }; | ||
455 | if iterate_method_candidates_by_receiver( | ||
456 | &ref_muted, | ||
457 | deref_chain, | ||
458 | db, | ||
459 | env, | ||
460 | krate, | ||
461 | &traits_in_scope, | ||
462 | name, | ||
463 | &mut callback, | ||
464 | ) { | ||
465 | return true; | ||
466 | } | ||
467 | false | ||
468 | } | ||
469 | |||
470 | fn iterate_method_candidates_by_receiver( | ||
471 | receiver_ty: &Canonical<Ty>, | ||
472 | rest_of_deref_chain: &[Canonical<Ty>], | ||
473 | db: &dyn HirDatabase, | ||
474 | env: Arc<TraitEnvironment>, | ||
475 | krate: CrateId, | ||
476 | traits_in_scope: &FxHashSet<TraitId>, | ||
477 | name: Option<&Name>, | ||
478 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
479 | ) -> bool { | ||
480 | // We're looking for methods with *receiver* type receiver_ty. These could | ||
481 | // be found in any of the derefs of receiver_ty, so we have to go through | ||
482 | // that. | ||
483 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { | ||
484 | if iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback) { | ||
485 | return true; | ||
486 | } | ||
487 | } | ||
488 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { | ||
489 | if iterate_trait_method_candidates( | ||
490 | self_ty, | ||
491 | db, | ||
492 | env.clone(), | ||
493 | krate, | ||
494 | &traits_in_scope, | ||
495 | name, | ||
496 | Some(receiver_ty), | ||
497 | &mut callback, | ||
498 | ) { | ||
499 | return true; | ||
500 | } | ||
501 | } | ||
502 | false | ||
503 | } | ||
504 | |||
505 | fn iterate_method_candidates_for_self_ty( | ||
506 | self_ty: &Canonical<Ty>, | ||
507 | db: &dyn HirDatabase, | ||
508 | env: Arc<TraitEnvironment>, | ||
509 | krate: CrateId, | ||
510 | traits_in_scope: &FxHashSet<TraitId>, | ||
511 | name: Option<&Name>, | ||
512 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
513 | ) -> bool { | ||
514 | if iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) { | ||
515 | return true; | ||
516 | } | ||
517 | iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback) | ||
518 | } | ||
519 | |||
520 | fn iterate_trait_method_candidates( | ||
521 | self_ty: &Canonical<Ty>, | ||
522 | db: &dyn HirDatabase, | ||
523 | env: Arc<TraitEnvironment>, | ||
524 | krate: CrateId, | ||
525 | traits_in_scope: &FxHashSet<TraitId>, | ||
526 | name: Option<&Name>, | ||
527 | receiver_ty: Option<&Canonical<Ty>>, | ||
528 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
529 | ) -> bool { | ||
530 | // if ty is `dyn Trait`, the trait doesn't need to be in scope | ||
531 | let inherent_trait = | ||
532 | self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); | ||
533 | let env_traits = if let Ty::Placeholder(_) = self_ty.value { | ||
534 | // if we have `T: Trait` in the param env, the trait doesn't need to be in scope | ||
535 | env.trait_predicates_for_self_ty(&self_ty.value) | ||
536 | .map(|tr| tr.trait_) | ||
537 | .flat_map(|t| all_super_traits(db.upcast(), t)) | ||
538 | .collect() | ||
539 | } else { | ||
540 | Vec::new() | ||
541 | }; | ||
542 | let traits = | ||
543 | inherent_trait.chain(env_traits.into_iter()).chain(traits_in_scope.iter().copied()); | ||
544 | 'traits: for t in traits { | ||
545 | let data = db.trait_data(t); | ||
546 | |||
547 | // we'll be lazy about checking whether the type implements the | ||
548 | // trait, but if we find out it doesn't, we'll skip the rest of the | ||
549 | // iteration | ||
550 | let mut known_implemented = false; | ||
551 | for (_name, item) in data.items.iter() { | ||
552 | if !is_valid_candidate(db, name, receiver_ty, *item, self_ty) { | ||
553 | continue; | ||
554 | } | ||
555 | if !known_implemented { | ||
556 | let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone()); | ||
557 | if db.trait_solve(krate, goal).is_none() { | ||
558 | continue 'traits; | ||
559 | } | ||
560 | } | ||
561 | known_implemented = true; | ||
562 | if callback(&self_ty.value, *item) { | ||
563 | return true; | ||
564 | } | ||
565 | } | ||
566 | } | ||
567 | false | ||
568 | } | ||
569 | |||
570 | fn iterate_inherent_methods( | ||
571 | self_ty: &Canonical<Ty>, | ||
572 | db: &dyn HirDatabase, | ||
573 | name: Option<&Name>, | ||
574 | receiver_ty: Option<&Canonical<Ty>>, | ||
575 | krate: CrateId, | ||
576 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
577 | ) -> bool { | ||
578 | let def_crates = match self_ty.value.def_crates(db, krate) { | ||
579 | Some(k) => k, | ||
580 | None => return false, | ||
581 | }; | ||
582 | for krate in def_crates { | ||
583 | let impls = db.inherent_impls_in_crate(krate); | ||
584 | |||
585 | for &impl_def in impls.for_self_ty(&self_ty.value) { | ||
586 | for &item in db.impl_data(impl_def).items.iter() { | ||
587 | if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { | ||
588 | continue; | ||
589 | } | ||
590 | // we have to check whether the self type unifies with the type | ||
591 | // that the impl is for. If we have a receiver type, this | ||
592 | // already happens in `is_valid_candidate` above; if not, we | ||
593 | // check it here | ||
594 | if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { | ||
595 | test_utils::mark::hit!(impl_self_type_match_without_receiver); | ||
596 | continue; | ||
597 | } | ||
598 | if callback(&self_ty.value, item) { | ||
599 | return true; | ||
600 | } | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | false | ||
605 | } | ||
606 | |||
607 | /// Returns the self type for the index trait call. | ||
608 | pub fn resolve_indexing_op( | ||
609 | db: &dyn HirDatabase, | ||
610 | ty: &Canonical<Ty>, | ||
611 | env: Arc<TraitEnvironment>, | ||
612 | krate: CrateId, | ||
613 | index_trait: TraitId, | ||
614 | ) -> Option<Canonical<Ty>> { | ||
615 | let ty = InEnvironment { value: ty.clone(), environment: env.clone() }; | ||
616 | let deref_chain = autoderef_method_receiver(db, krate, ty); | ||
617 | for ty in deref_chain { | ||
618 | let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone()); | ||
619 | if db.trait_solve(krate, goal).is_some() { | ||
620 | return Some(ty); | ||
621 | } | ||
622 | } | ||
623 | None | ||
624 | } | ||
625 | |||
626 | fn is_valid_candidate( | ||
627 | db: &dyn HirDatabase, | ||
628 | name: Option<&Name>, | ||
629 | receiver_ty: Option<&Canonical<Ty>>, | ||
630 | item: AssocItemId, | ||
631 | self_ty: &Canonical<Ty>, | ||
632 | ) -> bool { | ||
633 | match item { | ||
634 | AssocItemId::FunctionId(m) => { | ||
635 | let data = db.function_data(m); | ||
636 | if let Some(name) = name { | ||
637 | if &data.name != name { | ||
638 | return false; | ||
639 | } | ||
640 | } | ||
641 | if let Some(receiver_ty) = receiver_ty { | ||
642 | if !data.has_self_param { | ||
643 | return false; | ||
644 | } | ||
645 | let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) { | ||
646 | Some(ty) => ty, | ||
647 | None => return false, | ||
648 | }; | ||
649 | if transformed_receiver_ty != receiver_ty.value { | ||
650 | return false; | ||
651 | } | ||
652 | } | ||
653 | true | ||
654 | } | ||
655 | AssocItemId::ConstId(c) => { | ||
656 | let data = db.const_data(c); | ||
657 | name.map_or(true, |name| data.name.as_ref() == Some(name)) && receiver_ty.is_none() | ||
658 | } | ||
659 | _ => false, | ||
660 | } | ||
661 | } | ||
662 | |||
663 | pub(crate) fn inherent_impl_substs( | ||
664 | db: &dyn HirDatabase, | ||
665 | impl_id: ImplId, | ||
666 | self_ty: &Canonical<Ty>, | ||
667 | ) -> Option<Substs> { | ||
668 | // we create a var for each type parameter of the impl; we need to keep in | ||
669 | // mind here that `self_ty` might have vars of its own | ||
670 | let vars = Substs::build_for_def(db, impl_id) | ||
671 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.kinds.len()) | ||
672 | .build(); | ||
673 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); | ||
674 | let mut kinds = self_ty.kinds.to_vec(); | ||
675 | kinds.extend(iter::repeat(TyKind::General).take(vars.len())); | ||
676 | let tys = Canonical { kinds: kinds.into(), value: (self_ty_with_vars, self_ty.value.clone()) }; | ||
677 | let substs = super::infer::unify(&tys); | ||
678 | // We only want the substs for the vars we added, not the ones from self_ty. | ||
679 | // Also, if any of the vars we added are still in there, we replace them by | ||
680 | // Unknown. I think this can only really happen if self_ty contained | ||
681 | // Unknown, and in that case we want the result to contain Unknown in those | ||
682 | // places again. | ||
683 | substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.kinds.len())) | ||
684 | } | ||
685 | |||
686 | /// This replaces any 'free' Bound vars in `s` (i.e. those with indices past | ||
687 | /// num_vars_to_keep) by `Ty::Unknown`. | ||
688 | fn fallback_bound_vars(s: Substs, num_vars_to_keep: usize) -> Substs { | ||
689 | s.fold_binders( | ||
690 | &mut |ty, binders| { | ||
691 | if let Ty::Bound(bound) = &ty { | ||
692 | if bound.index >= num_vars_to_keep && bound.debruijn >= binders { | ||
693 | Ty::Unknown | ||
694 | } else { | ||
695 | ty | ||
696 | } | ||
697 | } else { | ||
698 | ty | ||
699 | } | ||
700 | }, | ||
701 | DebruijnIndex::INNERMOST, | ||
702 | ) | ||
703 | } | ||
704 | |||
705 | fn transform_receiver_ty( | ||
706 | db: &dyn HirDatabase, | ||
707 | function_id: FunctionId, | ||
708 | self_ty: &Canonical<Ty>, | ||
709 | ) -> Option<Ty> { | ||
710 | let substs = match function_id.lookup(db.upcast()).container { | ||
711 | AssocContainerId::TraitId(_) => Substs::build_for_def(db, function_id) | ||
712 | .push(self_ty.value.clone()) | ||
713 | .fill_with_unknown() | ||
714 | .build(), | ||
715 | AssocContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?, | ||
716 | AssocContainerId::ContainerId(_) => unreachable!(), | ||
717 | }; | ||
718 | let sig = db.callable_item_signature(function_id.into()); | ||
719 | Some(sig.value.params()[0].clone().subst_bound_vars(&substs)) | ||
720 | } | ||
721 | |||
722 | pub fn implements_trait( | ||
723 | ty: &Canonical<Ty>, | ||
724 | db: &dyn HirDatabase, | ||
725 | env: Arc<TraitEnvironment>, | ||
726 | krate: CrateId, | ||
727 | trait_: TraitId, | ||
728 | ) -> bool { | ||
729 | let goal = generic_implements_goal(db, env, trait_, ty.clone()); | ||
730 | let solution = db.trait_solve(krate, goal); | ||
731 | |||
732 | solution.is_some() | ||
733 | } | ||
734 | |||
735 | /// This creates Substs for a trait with the given Self type and type variables | ||
736 | /// for all other parameters, to query Chalk with it. | ||
737 | fn generic_implements_goal( | ||
738 | db: &dyn HirDatabase, | ||
739 | env: Arc<TraitEnvironment>, | ||
740 | trait_: TraitId, | ||
741 | self_ty: Canonical<Ty>, | ||
742 | ) -> Canonical<InEnvironment<super::Obligation>> { | ||
743 | let mut kinds = self_ty.kinds.to_vec(); | ||
744 | let substs = super::Substs::build_for_def(db, trait_) | ||
745 | .push(self_ty.value) | ||
746 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) | ||
747 | .build(); | ||
748 | kinds.extend(iter::repeat(TyKind::General).take(substs.len() - 1)); | ||
749 | let trait_ref = TraitRef { trait_, substs }; | ||
750 | let obligation = super::Obligation::Trait(trait_ref); | ||
751 | Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) } | ||
752 | } | ||
753 | |||
754 | fn autoderef_method_receiver( | ||
755 | db: &dyn HirDatabase, | ||
756 | krate: CrateId, | ||
757 | ty: InEnvironment<Canonical<Ty>>, | ||
758 | ) -> Vec<Canonical<Ty>> { | ||
759 | let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect(); | ||
760 | // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) | ||
761 | if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) = | ||
762 | deref_chain.last().map(|ty| &ty.value) | ||
763 | { | ||
764 | let kinds = deref_chain.last().unwrap().kinds.clone(); | ||
765 | let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone()); | ||
766 | deref_chain.push(Canonical { value: unsized_ty, kinds }) | ||
767 | } | ||
768 | deref_chain | ||
769 | } | ||
diff --git a/crates/hir_ty/src/op.rs b/crates/hir_ty/src/op.rs new file mode 100644 index 000000000..0870874fc --- /dev/null +++ b/crates/hir_ty/src/op.rs | |||
@@ -0,0 +1,58 @@ | |||
1 | //! Helper functions for binary operator type inference. | ||
2 | use hir_def::expr::{ArithOp, BinaryOp, CmpOp}; | ||
3 | |||
4 | use super::{InferTy, Ty, TypeCtor}; | ||
5 | use crate::ApplicationTy; | ||
6 | |||
7 | pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty { | ||
8 | match op { | ||
9 | BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => Ty::simple(TypeCtor::Bool), | ||
10 | BinaryOp::Assignment { .. } => Ty::unit(), | ||
11 | BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => match lhs_ty { | ||
12 | Ty::Apply(ApplicationTy { ctor, .. }) => match ctor { | ||
13 | TypeCtor::Int(..) | TypeCtor::Float(..) => lhs_ty, | ||
14 | _ => Ty::Unknown, | ||
15 | }, | ||
16 | Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty, | ||
17 | _ => Ty::Unknown, | ||
18 | }, | ||
19 | BinaryOp::ArithOp(_) => match rhs_ty { | ||
20 | Ty::Apply(ApplicationTy { ctor, .. }) => match ctor { | ||
21 | TypeCtor::Int(..) | TypeCtor::Float(..) => rhs_ty, | ||
22 | _ => Ty::Unknown, | ||
23 | }, | ||
24 | Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => rhs_ty, | ||
25 | _ => Ty::Unknown, | ||
26 | }, | ||
27 | } | ||
28 | } | ||
29 | |||
30 | pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty { | ||
31 | match op { | ||
32 | BinaryOp::LogicOp(..) => Ty::simple(TypeCtor::Bool), | ||
33 | BinaryOp::Assignment { op: None } => lhs_ty, | ||
34 | BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty { | ||
35 | Ty::Apply(ApplicationTy { ctor, .. }) => match ctor { | ||
36 | TypeCtor::Int(..) | ||
37 | | TypeCtor::Float(..) | ||
38 | | TypeCtor::Str | ||
39 | | TypeCtor::Char | ||
40 | | TypeCtor::Bool => lhs_ty, | ||
41 | _ => Ty::Unknown, | ||
42 | }, | ||
43 | Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty, | ||
44 | _ => Ty::Unknown, | ||
45 | }, | ||
46 | BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => Ty::Unknown, | ||
47 | BinaryOp::CmpOp(CmpOp::Ord { .. }) | ||
48 | | BinaryOp::Assignment { op: Some(_) } | ||
49 | | BinaryOp::ArithOp(_) => match lhs_ty { | ||
50 | Ty::Apply(ApplicationTy { ctor, .. }) => match ctor { | ||
51 | TypeCtor::Int(..) | TypeCtor::Float(..) => lhs_ty, | ||
52 | _ => Ty::Unknown, | ||
53 | }, | ||
54 | Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty, | ||
55 | _ => Ty::Unknown, | ||
56 | }, | ||
57 | } | ||
58 | } | ||
diff --git a/crates/hir_ty/src/primitive.rs b/crates/hir_ty/src/primitive.rs new file mode 100644 index 000000000..37966b709 --- /dev/null +++ b/crates/hir_ty/src/primitive.rs | |||
@@ -0,0 +1,139 @@ | |||
1 | //! Defines primitive types, which have a couple of peculiarities: | ||
2 | //! | ||
3 | //! * during type inference, they can be uncertain (ie, `let x = 92;`) | ||
4 | //! * they don't belong to any particular crate. | ||
5 | |||
6 | use std::fmt; | ||
7 | |||
8 | pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, FloatBitness, IntBitness, Signedness}; | ||
9 | |||
10 | #[derive(Copy, Clone, Eq, PartialEq, Hash)] | ||
11 | pub struct IntTy { | ||
12 | pub signedness: Signedness, | ||
13 | pub bitness: IntBitness, | ||
14 | } | ||
15 | |||
16 | impl fmt::Debug for IntTy { | ||
17 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
18 | fmt::Display::fmt(self, f) | ||
19 | } | ||
20 | } | ||
21 | |||
22 | impl fmt::Display for IntTy { | ||
23 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
24 | write!(f, "{}", self.ty_to_string()) | ||
25 | } | ||
26 | } | ||
27 | |||
28 | impl IntTy { | ||
29 | pub fn isize() -> IntTy { | ||
30 | IntTy { signedness: Signedness::Signed, bitness: IntBitness::Xsize } | ||
31 | } | ||
32 | |||
33 | pub fn i8() -> IntTy { | ||
34 | IntTy { signedness: Signedness::Signed, bitness: IntBitness::X8 } | ||
35 | } | ||
36 | |||
37 | pub fn i16() -> IntTy { | ||
38 | IntTy { signedness: Signedness::Signed, bitness: IntBitness::X16 } | ||
39 | } | ||
40 | |||
41 | pub fn i32() -> IntTy { | ||
42 | IntTy { signedness: Signedness::Signed, bitness: IntBitness::X32 } | ||
43 | } | ||
44 | |||
45 | pub fn i64() -> IntTy { | ||
46 | IntTy { signedness: Signedness::Signed, bitness: IntBitness::X64 } | ||
47 | } | ||
48 | |||
49 | pub fn i128() -> IntTy { | ||
50 | IntTy { signedness: Signedness::Signed, bitness: IntBitness::X128 } | ||
51 | } | ||
52 | |||
53 | pub fn usize() -> IntTy { | ||
54 | IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize } | ||
55 | } | ||
56 | |||
57 | pub fn u8() -> IntTy { | ||
58 | IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X8 } | ||
59 | } | ||
60 | |||
61 | pub fn u16() -> IntTy { | ||
62 | IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X16 } | ||
63 | } | ||
64 | |||
65 | pub fn u32() -> IntTy { | ||
66 | IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X32 } | ||
67 | } | ||
68 | |||
69 | pub fn u64() -> IntTy { | ||
70 | IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X64 } | ||
71 | } | ||
72 | |||
73 | pub fn u128() -> IntTy { | ||
74 | IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X128 } | ||
75 | } | ||
76 | |||
77 | pub fn ty_to_string(self) -> &'static str { | ||
78 | match (self.signedness, self.bitness) { | ||
79 | (Signedness::Signed, IntBitness::Xsize) => "isize", | ||
80 | (Signedness::Signed, IntBitness::X8) => "i8", | ||
81 | (Signedness::Signed, IntBitness::X16) => "i16", | ||
82 | (Signedness::Signed, IntBitness::X32) => "i32", | ||
83 | (Signedness::Signed, IntBitness::X64) => "i64", | ||
84 | (Signedness::Signed, IntBitness::X128) => "i128", | ||
85 | (Signedness::Unsigned, IntBitness::Xsize) => "usize", | ||
86 | (Signedness::Unsigned, IntBitness::X8) => "u8", | ||
87 | (Signedness::Unsigned, IntBitness::X16) => "u16", | ||
88 | (Signedness::Unsigned, IntBitness::X32) => "u32", | ||
89 | (Signedness::Unsigned, IntBitness::X64) => "u64", | ||
90 | (Signedness::Unsigned, IntBitness::X128) => "u128", | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
95 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] | ||
96 | pub struct FloatTy { | ||
97 | pub bitness: FloatBitness, | ||
98 | } | ||
99 | |||
100 | impl fmt::Debug for FloatTy { | ||
101 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
102 | fmt::Display::fmt(self, f) | ||
103 | } | ||
104 | } | ||
105 | |||
106 | impl fmt::Display for FloatTy { | ||
107 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
108 | write!(f, "{}", self.ty_to_string()) | ||
109 | } | ||
110 | } | ||
111 | |||
112 | impl FloatTy { | ||
113 | pub fn f32() -> FloatTy { | ||
114 | FloatTy { bitness: FloatBitness::X32 } | ||
115 | } | ||
116 | |||
117 | pub fn f64() -> FloatTy { | ||
118 | FloatTy { bitness: FloatBitness::X64 } | ||
119 | } | ||
120 | |||
121 | pub fn ty_to_string(self) -> &'static str { | ||
122 | match self.bitness { | ||
123 | FloatBitness::X32 => "f32", | ||
124 | FloatBitness::X64 => "f64", | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
129 | impl From<BuiltinInt> for IntTy { | ||
130 | fn from(t: BuiltinInt) -> Self { | ||
131 | IntTy { signedness: t.signedness, bitness: t.bitness } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | impl From<BuiltinFloat> for FloatTy { | ||
136 | fn from(t: BuiltinFloat) -> Self { | ||
137 | FloatTy { bitness: t.bitness } | ||
138 | } | ||
139 | } | ||
diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs new file mode 100644 index 000000000..15b8435e9 --- /dev/null +++ b/crates/hir_ty/src/test_db.rs | |||
@@ -0,0 +1,136 @@ | |||
1 | //! Database used for testing `hir`. | ||
2 | |||
3 | use std::{ | ||
4 | fmt, panic, | ||
5 | sync::{Arc, Mutex}, | ||
6 | }; | ||
7 | |||
8 | use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; | ||
9 | use hir_def::{db::DefDatabase, ModuleId}; | ||
10 | use hir_expand::db::AstDatabase; | ||
11 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
12 | use syntax::TextRange; | ||
13 | use test_utils::extract_annotations; | ||
14 | |||
15 | #[salsa::database( | ||
16 | base_db::SourceDatabaseExtStorage, | ||
17 | base_db::SourceDatabaseStorage, | ||
18 | hir_expand::db::AstDatabaseStorage, | ||
19 | hir_def::db::InternDatabaseStorage, | ||
20 | hir_def::db::DefDatabaseStorage, | ||
21 | crate::db::HirDatabaseStorage | ||
22 | )] | ||
23 | #[derive(Default)] | ||
24 | pub struct TestDB { | ||
25 | storage: salsa::Storage<TestDB>, | ||
26 | events: Mutex<Option<Vec<salsa::Event>>>, | ||
27 | } | ||
28 | impl fmt::Debug for TestDB { | ||
29 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
30 | f.debug_struct("TestDB").finish() | ||
31 | } | ||
32 | } | ||
33 | |||
34 | impl Upcast<dyn AstDatabase> for TestDB { | ||
35 | fn upcast(&self) -> &(dyn AstDatabase + 'static) { | ||
36 | &*self | ||
37 | } | ||
38 | } | ||
39 | |||
40 | impl Upcast<dyn DefDatabase> for TestDB { | ||
41 | fn upcast(&self) -> &(dyn DefDatabase + 'static) { | ||
42 | &*self | ||
43 | } | ||
44 | } | ||
45 | |||
46 | impl salsa::Database for TestDB { | ||
47 | fn salsa_event(&self, event: salsa::Event) { | ||
48 | let mut events = self.events.lock().unwrap(); | ||
49 | if let Some(events) = &mut *events { | ||
50 | events.push(event); | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | |||
55 | impl salsa::ParallelDatabase for TestDB { | ||
56 | fn snapshot(&self) -> salsa::Snapshot<TestDB> { | ||
57 | salsa::Snapshot::new(TestDB { | ||
58 | storage: self.storage.snapshot(), | ||
59 | events: Default::default(), | ||
60 | }) | ||
61 | } | ||
62 | } | ||
63 | |||
64 | impl panic::RefUnwindSafe for TestDB {} | ||
65 | |||
66 | impl FileLoader for TestDB { | ||
67 | fn file_text(&self, file_id: FileId) -> Arc<String> { | ||
68 | FileLoaderDelegate(self).file_text(file_id) | ||
69 | } | ||
70 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | ||
71 | FileLoaderDelegate(self).resolve_path(anchor, path) | ||
72 | } | ||
73 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { | ||
74 | FileLoaderDelegate(self).relevant_crates(file_id) | ||
75 | } | ||
76 | } | ||
77 | |||
78 | impl TestDB { | ||
79 | pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { | ||
80 | for &krate in self.relevant_crates(file_id).iter() { | ||
81 | let crate_def_map = self.crate_def_map(krate); | ||
82 | for (local_id, data) in crate_def_map.modules.iter() { | ||
83 | if data.origin.file_id() == Some(file_id) { | ||
84 | return ModuleId { krate, local_id }; | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | panic!("Can't find module for file") | ||
89 | } | ||
90 | |||
91 | pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { | ||
92 | let mut files = Vec::new(); | ||
93 | let crate_graph = self.crate_graph(); | ||
94 | for krate in crate_graph.iter() { | ||
95 | let crate_def_map = self.crate_def_map(krate); | ||
96 | for (module_id, _) in crate_def_map.modules.iter() { | ||
97 | let file_id = crate_def_map[module_id].origin.file_id(); | ||
98 | files.extend(file_id) | ||
99 | } | ||
100 | } | ||
101 | files | ||
102 | .into_iter() | ||
103 | .filter_map(|file_id| { | ||
104 | let text = self.file_text(file_id); | ||
105 | let annotations = extract_annotations(&text); | ||
106 | if annotations.is_empty() { | ||
107 | return None; | ||
108 | } | ||
109 | Some((file_id, annotations)) | ||
110 | }) | ||
111 | .collect() | ||
112 | } | ||
113 | } | ||
114 | |||
115 | impl TestDB { | ||
116 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> { | ||
117 | *self.events.lock().unwrap() = Some(Vec::new()); | ||
118 | f(); | ||
119 | self.events.lock().unwrap().take().unwrap() | ||
120 | } | ||
121 | |||
122 | pub fn log_executed(&self, f: impl FnOnce()) -> Vec<String> { | ||
123 | let events = self.log(f); | ||
124 | events | ||
125 | .into_iter() | ||
126 | .filter_map(|e| match e.kind { | ||
127 | // This pretty horrible, but `Debug` is the only way to inspect | ||
128 | // QueryDescriptor at the moment. | ||
129 | salsa::EventKind::WillExecute { database_key } => { | ||
130 | Some(format!("{:?}", database_key.debug(self))) | ||
131 | } | ||
132 | _ => None, | ||
133 | }) | ||
134 | .collect() | ||
135 | } | ||
136 | } | ||
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs new file mode 100644 index 000000000..c953925ec --- /dev/null +++ b/crates/hir_ty/src/tests.rs | |||
@@ -0,0 +1,359 @@ | |||
1 | mod never_type; | ||
2 | mod coercion; | ||
3 | mod regression; | ||
4 | mod simple; | ||
5 | mod patterns; | ||
6 | mod traits; | ||
7 | mod method_resolution; | ||
8 | mod macros; | ||
9 | mod display_source_code; | ||
10 | |||
11 | use std::sync::Arc; | ||
12 | |||
13 | use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; | ||
14 | use expect::Expect; | ||
15 | use hir_def::{ | ||
16 | body::{BodySourceMap, SyntheticSyntax}, | ||
17 | child_by_source::ChildBySource, | ||
18 | db::DefDatabase, | ||
19 | item_scope::ItemScope, | ||
20 | keys, | ||
21 | nameres::CrateDefMap, | ||
22 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, | ||
23 | }; | ||
24 | use hir_expand::{db::AstDatabase, InFile}; | ||
25 | use stdx::format_to; | ||
26 | use syntax::{ | ||
27 | algo, | ||
28 | ast::{self, AstNode}, | ||
29 | SyntaxNode, | ||
30 | }; | ||
31 | |||
32 | use crate::{ | ||
33 | db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, | ||
34 | }; | ||
35 | |||
36 | // These tests compare the inference results for all expressions in a file | ||
37 | // against snapshots of the expected results using expect. Use | ||
38 | // `env UPDATE_EXPECT=1 cargo test -p hir_ty` to update the snapshots. | ||
39 | |||
40 | fn setup_tracing() -> tracing::subscriber::DefaultGuard { | ||
41 | use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; | ||
42 | use tracing_tree::HierarchicalLayer; | ||
43 | let filter = EnvFilter::from_env("CHALK_DEBUG"); | ||
44 | let layer = HierarchicalLayer::default() | ||
45 | .with_indent_lines(true) | ||
46 | .with_ansi(false) | ||
47 | .with_indent_amount(2) | ||
48 | .with_writer(std::io::stderr); | ||
49 | let subscriber = Registry::default().with(filter).with(layer); | ||
50 | tracing::subscriber::set_default(subscriber) | ||
51 | } | ||
52 | |||
53 | fn check_types(ra_fixture: &str) { | ||
54 | check_types_impl(ra_fixture, false) | ||
55 | } | ||
56 | |||
57 | fn check_types_source_code(ra_fixture: &str) { | ||
58 | check_types_impl(ra_fixture, true) | ||
59 | } | ||
60 | |||
61 | fn check_types_impl(ra_fixture: &str, display_source: bool) { | ||
62 | let _tracing = setup_tracing(); | ||
63 | let db = TestDB::with_files(ra_fixture); | ||
64 | let mut checked_one = false; | ||
65 | for (file_id, annotations) in db.extract_annotations() { | ||
66 | for (range, expected) in annotations { | ||
67 | let ty = type_at_range(&db, FileRange { file_id, range }); | ||
68 | let actual = if display_source { | ||
69 | let module = db.module_for_file(file_id); | ||
70 | ty.display_source_code(&db, module).unwrap() | ||
71 | } else { | ||
72 | ty.display(&db).to_string() | ||
73 | }; | ||
74 | assert_eq!(expected, actual); | ||
75 | checked_one = true; | ||
76 | } | ||
77 | } | ||
78 | assert!(checked_one, "no `//^` annotations found"); | ||
79 | } | ||
80 | |||
81 | fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { | ||
82 | let file = db.parse(pos.file_id).ok().unwrap(); | ||
83 | let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); | ||
84 | let fn_def = expr.syntax().ancestors().find_map(ast::Fn::cast).unwrap(); | ||
85 | let module = db.module_for_file(pos.file_id); | ||
86 | let func = *module.child_by_source(db)[keys::FUNCTION] | ||
87 | .get(&InFile::new(pos.file_id.into(), fn_def)) | ||
88 | .unwrap(); | ||
89 | |||
90 | let (_body, source_map) = db.body_with_source_map(func.into()); | ||
91 | if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { | ||
92 | let infer = db.infer(func.into()); | ||
93 | return infer[expr_id].clone(); | ||
94 | } | ||
95 | panic!("Can't find expression") | ||
96 | } | ||
97 | |||
98 | fn infer(ra_fixture: &str) -> String { | ||
99 | infer_with_mismatches(ra_fixture, false) | ||
100 | } | ||
101 | |||
102 | fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | ||
103 | let _tracing = setup_tracing(); | ||
104 | let (db, file_id) = TestDB::with_single_file(content); | ||
105 | |||
106 | let mut buf = String::new(); | ||
107 | |||
108 | let mut infer_def = |inference_result: Arc<InferenceResult>, | ||
109 | body_source_map: Arc<BodySourceMap>| { | ||
110 | let mut types: Vec<(InFile<SyntaxNode>, &Ty)> = Vec::new(); | ||
111 | let mut mismatches: Vec<(InFile<SyntaxNode>, &TypeMismatch)> = Vec::new(); | ||
112 | |||
113 | for (pat, ty) in inference_result.type_of_pat.iter() { | ||
114 | let syntax_ptr = match body_source_map.pat_syntax(pat) { | ||
115 | Ok(sp) => { | ||
116 | let root = db.parse_or_expand(sp.file_id).unwrap(); | ||
117 | sp.map(|ptr| { | ||
118 | ptr.either( | ||
119 | |it| it.to_node(&root).syntax().clone(), | ||
120 | |it| it.to_node(&root).syntax().clone(), | ||
121 | ) | ||
122 | }) | ||
123 | } | ||
124 | Err(SyntheticSyntax) => continue, | ||
125 | }; | ||
126 | types.push((syntax_ptr, ty)); | ||
127 | } | ||
128 | |||
129 | for (expr, ty) in inference_result.type_of_expr.iter() { | ||
130 | let node = match body_source_map.expr_syntax(expr) { | ||
131 | Ok(sp) => { | ||
132 | let root = db.parse_or_expand(sp.file_id).unwrap(); | ||
133 | sp.map(|ptr| ptr.to_node(&root).syntax().clone()) | ||
134 | } | ||
135 | Err(SyntheticSyntax) => continue, | ||
136 | }; | ||
137 | types.push((node.clone(), ty)); | ||
138 | if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { | ||
139 | mismatches.push((node, mismatch)); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | // sort ranges for consistency | ||
144 | types.sort_by_key(|(node, _)| { | ||
145 | let range = node.value.text_range(); | ||
146 | (range.start(), range.end()) | ||
147 | }); | ||
148 | for (node, ty) in &types { | ||
149 | let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) { | ||
150 | (self_param.self_token().unwrap().text_range(), "self".to_string()) | ||
151 | } else { | ||
152 | (node.value.text_range(), node.value.text().to_string().replace("\n", " ")) | ||
153 | }; | ||
154 | let macro_prefix = if node.file_id != file_id.into() { "!" } else { "" }; | ||
155 | format_to!( | ||
156 | buf, | ||
157 | "{}{:?} '{}': {}\n", | ||
158 | macro_prefix, | ||
159 | range, | ||
160 | ellipsize(text, 15), | ||
161 | ty.display(&db) | ||
162 | ); | ||
163 | } | ||
164 | if include_mismatches { | ||
165 | mismatches.sort_by_key(|(node, _)| { | ||
166 | let range = node.value.text_range(); | ||
167 | (range.start(), range.end()) | ||
168 | }); | ||
169 | for (src_ptr, mismatch) in &mismatches { | ||
170 | let range = src_ptr.value.text_range(); | ||
171 | let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" }; | ||
172 | format_to!( | ||
173 | buf, | ||
174 | "{}{:?}: expected {}, got {}\n", | ||
175 | macro_prefix, | ||
176 | range, | ||
177 | mismatch.expected.display(&db), | ||
178 | mismatch.actual.display(&db), | ||
179 | ); | ||
180 | } | ||
181 | } | ||
182 | }; | ||
183 | |||
184 | let module = db.module_for_file(file_id); | ||
185 | let crate_def_map = db.crate_def_map(module.krate); | ||
186 | |||
187 | let mut defs: Vec<DefWithBodyId> = Vec::new(); | ||
188 | visit_module(&db, &crate_def_map, module.local_id, &mut |it| defs.push(it)); | ||
189 | defs.sort_by_key(|def| match def { | ||
190 | DefWithBodyId::FunctionId(it) => { | ||
191 | let loc = it.lookup(&db); | ||
192 | let tree = db.item_tree(loc.id.file_id); | ||
193 | tree.source(&db, loc.id).syntax().text_range().start() | ||
194 | } | ||
195 | DefWithBodyId::ConstId(it) => { | ||
196 | let loc = it.lookup(&db); | ||
197 | let tree = db.item_tree(loc.id.file_id); | ||
198 | tree.source(&db, loc.id).syntax().text_range().start() | ||
199 | } | ||
200 | DefWithBodyId::StaticId(it) => { | ||
201 | let loc = it.lookup(&db); | ||
202 | let tree = db.item_tree(loc.id.file_id); | ||
203 | tree.source(&db, loc.id).syntax().text_range().start() | ||
204 | } | ||
205 | }); | ||
206 | for def in defs { | ||
207 | let (_body, source_map) = db.body_with_source_map(def); | ||
208 | let infer = db.infer(def); | ||
209 | infer_def(infer, source_map); | ||
210 | } | ||
211 | |||
212 | buf.truncate(buf.trim_end().len()); | ||
213 | buf | ||
214 | } | ||
215 | |||
216 | fn visit_module( | ||
217 | db: &TestDB, | ||
218 | crate_def_map: &CrateDefMap, | ||
219 | module_id: LocalModuleId, | ||
220 | cb: &mut dyn FnMut(DefWithBodyId), | ||
221 | ) { | ||
222 | visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb); | ||
223 | for impl_id in crate_def_map[module_id].scope.impls() { | ||
224 | let impl_data = db.impl_data(impl_id); | ||
225 | for &item in impl_data.items.iter() { | ||
226 | match item { | ||
227 | AssocItemId::FunctionId(it) => { | ||
228 | let def = it.into(); | ||
229 | cb(def); | ||
230 | let body = db.body(def); | ||
231 | visit_scope(db, crate_def_map, &body.item_scope, cb); | ||
232 | } | ||
233 | AssocItemId::ConstId(it) => { | ||
234 | let def = it.into(); | ||
235 | cb(def); | ||
236 | let body = db.body(def); | ||
237 | visit_scope(db, crate_def_map, &body.item_scope, cb); | ||
238 | } | ||
239 | AssocItemId::TypeAliasId(_) => (), | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | |||
244 | fn visit_scope( | ||
245 | db: &TestDB, | ||
246 | crate_def_map: &CrateDefMap, | ||
247 | scope: &ItemScope, | ||
248 | cb: &mut dyn FnMut(DefWithBodyId), | ||
249 | ) { | ||
250 | for decl in scope.declarations() { | ||
251 | match decl { | ||
252 | ModuleDefId::FunctionId(it) => { | ||
253 | let def = it.into(); | ||
254 | cb(def); | ||
255 | let body = db.body(def); | ||
256 | visit_scope(db, crate_def_map, &body.item_scope, cb); | ||
257 | } | ||
258 | ModuleDefId::ConstId(it) => { | ||
259 | let def = it.into(); | ||
260 | cb(def); | ||
261 | let body = db.body(def); | ||
262 | visit_scope(db, crate_def_map, &body.item_scope, cb); | ||
263 | } | ||
264 | ModuleDefId::StaticId(it) => { | ||
265 | let def = it.into(); | ||
266 | cb(def); | ||
267 | let body = db.body(def); | ||
268 | visit_scope(db, crate_def_map, &body.item_scope, cb); | ||
269 | } | ||
270 | ModuleDefId::TraitId(it) => { | ||
271 | let trait_data = db.trait_data(it); | ||
272 | for &(_, item) in trait_data.items.iter() { | ||
273 | match item { | ||
274 | AssocItemId::FunctionId(it) => cb(it.into()), | ||
275 | AssocItemId::ConstId(it) => cb(it.into()), | ||
276 | AssocItemId::TypeAliasId(_) => (), | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | ModuleDefId::ModuleId(it) => visit_module(db, crate_def_map, it.local_id, cb), | ||
281 | _ => (), | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | |||
287 | fn ellipsize(mut text: String, max_len: usize) -> String { | ||
288 | if text.len() <= max_len { | ||
289 | return text; | ||
290 | } | ||
291 | let ellipsis = "..."; | ||
292 | let e_len = ellipsis.len(); | ||
293 | let mut prefix_len = (max_len - e_len) / 2; | ||
294 | while !text.is_char_boundary(prefix_len) { | ||
295 | prefix_len += 1; | ||
296 | } | ||
297 | let mut suffix_len = max_len - e_len - prefix_len; | ||
298 | while !text.is_char_boundary(text.len() - suffix_len) { | ||
299 | suffix_len += 1; | ||
300 | } | ||
301 | text.replace_range(prefix_len..text.len() - suffix_len, ellipsis); | ||
302 | text | ||
303 | } | ||
304 | |||
305 | #[test] | ||
306 | fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | ||
307 | let (mut db, pos) = TestDB::with_position( | ||
308 | " | ||
309 | //- /lib.rs | ||
310 | fn foo() -> i32 { | ||
311 | <|>1 + 1 | ||
312 | } | ||
313 | ", | ||
314 | ); | ||
315 | { | ||
316 | let events = db.log_executed(|| { | ||
317 | let module = db.module_for_file(pos.file_id); | ||
318 | let crate_def_map = db.crate_def_map(module.krate); | ||
319 | visit_module(&db, &crate_def_map, module.local_id, &mut |def| { | ||
320 | db.infer(def); | ||
321 | }); | ||
322 | }); | ||
323 | assert!(format!("{:?}", events).contains("infer")) | ||
324 | } | ||
325 | |||
326 | let new_text = " | ||
327 | fn foo() -> i32 { | ||
328 | 1 | ||
329 | + | ||
330 | 1 | ||
331 | } | ||
332 | " | ||
333 | .to_string(); | ||
334 | |||
335 | db.set_file_text(pos.file_id, Arc::new(new_text)); | ||
336 | |||
337 | { | ||
338 | let events = db.log_executed(|| { | ||
339 | let module = db.module_for_file(pos.file_id); | ||
340 | let crate_def_map = db.crate_def_map(module.krate); | ||
341 | visit_module(&db, &crate_def_map, module.local_id, &mut |def| { | ||
342 | db.infer(def); | ||
343 | }); | ||
344 | }); | ||
345 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) | ||
346 | } | ||
347 | } | ||
348 | |||
349 | fn check_infer(ra_fixture: &str, expect: Expect) { | ||
350 | let mut actual = infer(ra_fixture); | ||
351 | actual.push('\n'); | ||
352 | expect.assert_eq(&actual); | ||
353 | } | ||
354 | |||
355 | fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) { | ||
356 | let mut actual = infer_with_mismatches(ra_fixture, true); | ||
357 | actual.push('\n'); | ||
358 | expect.assert_eq(&actual); | ||
359 | } | ||
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs new file mode 100644 index 000000000..17efd75cb --- /dev/null +++ b/crates/hir_ty/src/tests/coercion.rs | |||
@@ -0,0 +1,861 @@ | |||
1 | use expect::expect; | ||
2 | use test_utils::mark; | ||
3 | |||
4 | use super::{check_infer, check_infer_with_mismatches}; | ||
5 | |||
6 | #[test] | ||
7 | fn infer_block_expr_type_mismatch() { | ||
8 | check_infer( | ||
9 | r" | ||
10 | fn test() { | ||
11 | let a: i32 = { 1i64 }; | ||
12 | } | ||
13 | ", | ||
14 | expect![[r" | ||
15 | 10..40 '{ ...4 }; }': () | ||
16 | 20..21 'a': i32 | ||
17 | 29..37 '{ 1i64 }': i64 | ||
18 | 31..35 '1i64': i64 | ||
19 | "]], | ||
20 | ); | ||
21 | } | ||
22 | |||
23 | #[test] | ||
24 | fn coerce_places() { | ||
25 | check_infer( | ||
26 | r#" | ||
27 | struct S<T> { a: T } | ||
28 | |||
29 | fn f<T>(_: &[T]) -> T { loop {} } | ||
30 | fn g<T>(_: S<&[T]>) -> T { loop {} } | ||
31 | |||
32 | fn gen<T>() -> *mut [T; 2] { loop {} } | ||
33 | fn test1<U>() -> *mut [U] { | ||
34 | gen() | ||
35 | } | ||
36 | |||
37 | fn test2() { | ||
38 | let arr: &[u8; 1] = &[1]; | ||
39 | |||
40 | let a: &[_] = arr; | ||
41 | let b = f(arr); | ||
42 | let c: &[_] = { arr }; | ||
43 | let d = g(S { a: arr }); | ||
44 | let e: [&[_]; 1] = [arr]; | ||
45 | let f: [&[_]; 2] = [arr; 2]; | ||
46 | let g: (&[_], &[_]) = (arr, arr); | ||
47 | } | ||
48 | |||
49 | #[lang = "sized"] | ||
50 | pub trait Sized {} | ||
51 | #[lang = "unsize"] | ||
52 | pub trait Unsize<T: ?Sized> {} | ||
53 | #[lang = "coerce_unsized"] | ||
54 | pub trait CoerceUnsized<T> {} | ||
55 | |||
56 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
57 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
58 | "#, | ||
59 | expect![[r" | ||
60 | 30..31 '_': &[T] | ||
61 | 44..55 '{ loop {} }': T | ||
62 | 46..53 'loop {}': ! | ||
63 | 51..53 '{}': () | ||
64 | 64..65 '_': S<&[T]> | ||
65 | 81..92 '{ loop {} }': T | ||
66 | 83..90 'loop {}': ! | ||
67 | 88..90 '{}': () | ||
68 | 121..132 '{ loop {} }': *mut [T; _] | ||
69 | 123..130 'loop {}': ! | ||
70 | 128..130 '{}': () | ||
71 | 159..172 '{ gen() }': *mut [U] | ||
72 | 165..168 'gen': fn gen<U>() -> *mut [U; _] | ||
73 | 165..170 'gen()': *mut [U; _] | ||
74 | 185..419 '{ ...rr); }': () | ||
75 | 195..198 'arr': &[u8; _] | ||
76 | 211..215 '&[1]': &[u8; _] | ||
77 | 212..215 '[1]': [u8; _] | ||
78 | 213..214 '1': u8 | ||
79 | 226..227 'a': &[u8] | ||
80 | 236..239 'arr': &[u8; _] | ||
81 | 249..250 'b': u8 | ||
82 | 253..254 'f': fn f<u8>(&[u8]) -> u8 | ||
83 | 253..259 'f(arr)': u8 | ||
84 | 255..258 'arr': &[u8; _] | ||
85 | 269..270 'c': &[u8] | ||
86 | 279..286 '{ arr }': &[u8] | ||
87 | 281..284 'arr': &[u8; _] | ||
88 | 296..297 'd': u8 | ||
89 | 300..301 'g': fn g<u8>(S<&[u8]>) -> u8 | ||
90 | 300..315 'g(S { a: arr })': u8 | ||
91 | 302..314 'S { a: arr }': S<&[u8]> | ||
92 | 309..312 'arr': &[u8; _] | ||
93 | 325..326 'e': [&[u8]; _] | ||
94 | 340..345 '[arr]': [&[u8]; _] | ||
95 | 341..344 'arr': &[u8; _] | ||
96 | 355..356 'f': [&[u8]; _] | ||
97 | 370..378 '[arr; 2]': [&[u8]; _] | ||
98 | 371..374 'arr': &[u8; _] | ||
99 | 376..377 '2': usize | ||
100 | 388..389 'g': (&[u8], &[u8]) | ||
101 | 406..416 '(arr, arr)': (&[u8], &[u8]) | ||
102 | 407..410 'arr': &[u8; _] | ||
103 | 412..415 'arr': &[u8; _] | ||
104 | "]], | ||
105 | ); | ||
106 | } | ||
107 | |||
108 | #[test] | ||
109 | fn infer_let_stmt_coerce() { | ||
110 | check_infer( | ||
111 | r" | ||
112 | fn test() { | ||
113 | let x: &[isize] = &[1]; | ||
114 | let x: *const [isize] = &[1]; | ||
115 | } | ||
116 | ", | ||
117 | expect![[r" | ||
118 | 10..75 '{ ...[1]; }': () | ||
119 | 20..21 'x': &[isize] | ||
120 | 34..38 '&[1]': &[isize; _] | ||
121 | 35..38 '[1]': [isize; _] | ||
122 | 36..37 '1': isize | ||
123 | 48..49 'x': *const [isize] | ||
124 | 68..72 '&[1]': &[isize; _] | ||
125 | 69..72 '[1]': [isize; _] | ||
126 | 70..71 '1': isize | ||
127 | "]], | ||
128 | ); | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn infer_custom_coerce_unsized() { | ||
133 | check_infer( | ||
134 | r#" | ||
135 | struct A<T: ?Sized>(*const T); | ||
136 | struct B<T: ?Sized>(*const T); | ||
137 | struct C<T: ?Sized> { inner: *const T } | ||
138 | |||
139 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} | ||
140 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} | ||
141 | |||
142 | fn foo1<T>(x: A<[T]>) -> A<[T]> { x } | ||
143 | fn foo2<T>(x: B<[T]>) -> B<[T]> { x } | ||
144 | fn foo3<T>(x: C<[T]>) -> C<[T]> { x } | ||
145 | |||
146 | fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { | ||
147 | let d = foo1(a); | ||
148 | let e = foo2(b); | ||
149 | let f = foo3(c); | ||
150 | } | ||
151 | |||
152 | |||
153 | #[lang = "sized"] | ||
154 | pub trait Sized {} | ||
155 | #[lang = "unsize"] | ||
156 | pub trait Unsize<T: ?Sized> {} | ||
157 | #[lang = "coerce_unsized"] | ||
158 | pub trait CoerceUnsized<T> {} | ||
159 | |||
160 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
161 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
162 | "#, | ||
163 | expect![[r" | ||
164 | 257..258 'x': A<[T]> | ||
165 | 278..283 '{ x }': A<[T]> | ||
166 | 280..281 'x': A<[T]> | ||
167 | 295..296 'x': B<[T]> | ||
168 | 316..321 '{ x }': B<[T]> | ||
169 | 318..319 'x': B<[T]> | ||
170 | 333..334 'x': C<[T]> | ||
171 | 354..359 '{ x }': C<[T]> | ||
172 | 356..357 'x': C<[T]> | ||
173 | 369..370 'a': A<[u8; _]> | ||
174 | 384..385 'b': B<[u8; _]> | ||
175 | 399..400 'c': C<[u8; _]> | ||
176 | 414..480 '{ ...(c); }': () | ||
177 | 424..425 'd': A<[{unknown}]> | ||
178 | 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> | ||
179 | 428..435 'foo1(a)': A<[{unknown}]> | ||
180 | 433..434 'a': A<[u8; _]> | ||
181 | 445..446 'e': B<[u8]> | ||
182 | 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> | ||
183 | 449..456 'foo2(b)': B<[u8]> | ||
184 | 454..455 'b': B<[u8; _]> | ||
185 | 466..467 'f': C<[u8]> | ||
186 | 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> | ||
187 | 470..477 'foo3(c)': C<[u8]> | ||
188 | 475..476 'c': C<[u8; _]> | ||
189 | "]], | ||
190 | ); | ||
191 | } | ||
192 | |||
193 | #[test] | ||
194 | fn infer_if_coerce() { | ||
195 | check_infer( | ||
196 | r#" | ||
197 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
198 | fn test() { | ||
199 | let x = if true { | ||
200 | foo(&[1]) | ||
201 | } else { | ||
202 | &[1] | ||
203 | }; | ||
204 | } | ||
205 | |||
206 | |||
207 | #[lang = "sized"] | ||
208 | pub trait Sized {} | ||
209 | #[lang = "unsize"] | ||
210 | pub trait Unsize<T: ?Sized> {} | ||
211 | "#, | ||
212 | expect![[r" | ||
213 | 10..11 'x': &[T] | ||
214 | 27..38 '{ loop {} }': &[T] | ||
215 | 29..36 'loop {}': ! | ||
216 | 34..36 '{}': () | ||
217 | 49..125 '{ ... }; }': () | ||
218 | 59..60 'x': &[i32] | ||
219 | 63..122 'if tru... }': &[i32] | ||
220 | 66..70 'true': bool | ||
221 | 71..96 '{ ... }': &[i32] | ||
222 | 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
223 | 81..90 'foo(&[1])': &[i32] | ||
224 | 85..89 '&[1]': &[i32; _] | ||
225 | 86..89 '[1]': [i32; _] | ||
226 | 87..88 '1': i32 | ||
227 | 102..122 '{ ... }': &[i32; _] | ||
228 | 112..116 '&[1]': &[i32; _] | ||
229 | 113..116 '[1]': [i32; _] | ||
230 | 114..115 '1': i32 | ||
231 | "]], | ||
232 | ); | ||
233 | } | ||
234 | |||
235 | #[test] | ||
236 | fn infer_if_else_coerce() { | ||
237 | check_infer( | ||
238 | r#" | ||
239 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
240 | fn test() { | ||
241 | let x = if true { | ||
242 | &[1] | ||
243 | } else { | ||
244 | foo(&[1]) | ||
245 | }; | ||
246 | } | ||
247 | |||
248 | #[lang = "sized"] | ||
249 | pub trait Sized {} | ||
250 | #[lang = "unsize"] | ||
251 | pub trait Unsize<T: ?Sized> {} | ||
252 | #[lang = "coerce_unsized"] | ||
253 | pub trait CoerceUnsized<T> {} | ||
254 | |||
255 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
256 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
257 | "#, | ||
258 | expect![[r" | ||
259 | 10..11 'x': &[T] | ||
260 | 27..38 '{ loop {} }': &[T] | ||
261 | 29..36 'loop {}': ! | ||
262 | 34..36 '{}': () | ||
263 | 49..125 '{ ... }; }': () | ||
264 | 59..60 'x': &[i32] | ||
265 | 63..122 'if tru... }': &[i32] | ||
266 | 66..70 'true': bool | ||
267 | 71..91 '{ ... }': &[i32; _] | ||
268 | 81..85 '&[1]': &[i32; _] | ||
269 | 82..85 '[1]': [i32; _] | ||
270 | 83..84 '1': i32 | ||
271 | 97..122 '{ ... }': &[i32] | ||
272 | 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
273 | 107..116 'foo(&[1])': &[i32] | ||
274 | 111..115 '&[1]': &[i32; _] | ||
275 | 112..115 '[1]': [i32; _] | ||
276 | 113..114 '1': i32 | ||
277 | "]], | ||
278 | ) | ||
279 | } | ||
280 | |||
281 | #[test] | ||
282 | fn infer_match_first_coerce() { | ||
283 | check_infer( | ||
284 | r#" | ||
285 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
286 | fn test(i: i32) { | ||
287 | let x = match i { | ||
288 | 2 => foo(&[2]), | ||
289 | 1 => &[1], | ||
290 | _ => &[3], | ||
291 | }; | ||
292 | } | ||
293 | |||
294 | #[lang = "sized"] | ||
295 | pub trait Sized {} | ||
296 | #[lang = "unsize"] | ||
297 | pub trait Unsize<T: ?Sized> {} | ||
298 | "#, | ||
299 | expect![[r" | ||
300 | 10..11 'x': &[T] | ||
301 | 27..38 '{ loop {} }': &[T] | ||
302 | 29..36 'loop {}': ! | ||
303 | 34..36 '{}': () | ||
304 | 47..48 'i': i32 | ||
305 | 55..149 '{ ... }; }': () | ||
306 | 65..66 'x': &[i32] | ||
307 | 69..146 'match ... }': &[i32] | ||
308 | 75..76 'i': i32 | ||
309 | 87..88 '2': i32 | ||
310 | 87..88 '2': i32 | ||
311 | 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
312 | 92..101 'foo(&[2])': &[i32] | ||
313 | 96..100 '&[2]': &[i32; _] | ||
314 | 97..100 '[2]': [i32; _] | ||
315 | 98..99 '2': i32 | ||
316 | 111..112 '1': i32 | ||
317 | 111..112 '1': i32 | ||
318 | 116..120 '&[1]': &[i32; _] | ||
319 | 117..120 '[1]': [i32; _] | ||
320 | 118..119 '1': i32 | ||
321 | 130..131 '_': i32 | ||
322 | 135..139 '&[3]': &[i32; _] | ||
323 | 136..139 '[3]': [i32; _] | ||
324 | 137..138 '3': i32 | ||
325 | "]], | ||
326 | ); | ||
327 | } | ||
328 | |||
329 | #[test] | ||
330 | fn infer_match_second_coerce() { | ||
331 | check_infer( | ||
332 | r#" | ||
333 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
334 | fn test(i: i32) { | ||
335 | let x = match i { | ||
336 | 1 => &[1], | ||
337 | 2 => foo(&[2]), | ||
338 | _ => &[3], | ||
339 | }; | ||
340 | } | ||
341 | |||
342 | #[lang = "sized"] | ||
343 | pub trait Sized {} | ||
344 | #[lang = "unsize"] | ||
345 | pub trait Unsize<T: ?Sized> {} | ||
346 | #[lang = "coerce_unsized"] | ||
347 | pub trait CoerceUnsized<T> {} | ||
348 | |||
349 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
350 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
351 | "#, | ||
352 | expect![[r" | ||
353 | 10..11 'x': &[T] | ||
354 | 27..38 '{ loop {} }': &[T] | ||
355 | 29..36 'loop {}': ! | ||
356 | 34..36 '{}': () | ||
357 | 47..48 'i': i32 | ||
358 | 55..149 '{ ... }; }': () | ||
359 | 65..66 'x': &[i32] | ||
360 | 69..146 'match ... }': &[i32] | ||
361 | 75..76 'i': i32 | ||
362 | 87..88 '1': i32 | ||
363 | 87..88 '1': i32 | ||
364 | 92..96 '&[1]': &[i32; _] | ||
365 | 93..96 '[1]': [i32; _] | ||
366 | 94..95 '1': i32 | ||
367 | 106..107 '2': i32 | ||
368 | 106..107 '2': i32 | ||
369 | 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
370 | 111..120 'foo(&[2])': &[i32] | ||
371 | 115..119 '&[2]': &[i32; _] | ||
372 | 116..119 '[2]': [i32; _] | ||
373 | 117..118 '2': i32 | ||
374 | 130..131 '_': i32 | ||
375 | 135..139 '&[3]': &[i32; _] | ||
376 | 136..139 '[3]': [i32; _] | ||
377 | 137..138 '3': i32 | ||
378 | "]], | ||
379 | ); | ||
380 | } | ||
381 | |||
382 | #[test] | ||
383 | fn coerce_merge_one_by_one1() { | ||
384 | mark::check!(coerce_merge_fail_fallback); | ||
385 | |||
386 | check_infer( | ||
387 | r" | ||
388 | fn test() { | ||
389 | let t = &mut 1; | ||
390 | let x = match 1 { | ||
391 | 1 => t as *mut i32, | ||
392 | 2 => t as &i32, | ||
393 | _ => t as *const i32, | ||
394 | }; | ||
395 | } | ||
396 | ", | ||
397 | expect![[r" | ||
398 | 10..144 '{ ... }; }': () | ||
399 | 20..21 't': &mut i32 | ||
400 | 24..30 '&mut 1': &mut i32 | ||
401 | 29..30 '1': i32 | ||
402 | 40..41 'x': *const i32 | ||
403 | 44..141 'match ... }': *const i32 | ||
404 | 50..51 '1': i32 | ||
405 | 62..63 '1': i32 | ||
406 | 62..63 '1': i32 | ||
407 | 67..68 't': &mut i32 | ||
408 | 67..80 't as *mut i32': *mut i32 | ||
409 | 90..91 '2': i32 | ||
410 | 90..91 '2': i32 | ||
411 | 95..96 't': &mut i32 | ||
412 | 95..104 't as &i32': &i32 | ||
413 | 114..115 '_': i32 | ||
414 | 119..120 't': &mut i32 | ||
415 | 119..134 't as *const i32': *const i32 | ||
416 | "]], | ||
417 | ); | ||
418 | } | ||
419 | |||
420 | #[test] | ||
421 | fn return_coerce_unknown() { | ||
422 | check_infer_with_mismatches( | ||
423 | r" | ||
424 | fn foo() -> u32 { | ||
425 | return unknown; | ||
426 | } | ||
427 | ", | ||
428 | expect![[r" | ||
429 | 16..39 '{ ...own; }': u32 | ||
430 | 22..36 'return unknown': ! | ||
431 | 29..36 'unknown': u32 | ||
432 | "]], | ||
433 | ); | ||
434 | } | ||
435 | |||
436 | #[test] | ||
437 | fn coerce_autoderef() { | ||
438 | check_infer_with_mismatches( | ||
439 | r" | ||
440 | struct Foo; | ||
441 | fn takes_ref_foo(x: &Foo) {} | ||
442 | fn test() { | ||
443 | takes_ref_foo(&Foo); | ||
444 | takes_ref_foo(&&Foo); | ||
445 | takes_ref_foo(&&&Foo); | ||
446 | } | ||
447 | ", | ||
448 | expect![[r" | ||
449 | 29..30 'x': &Foo | ||
450 | 38..40 '{}': () | ||
451 | 51..132 '{ ...oo); }': () | ||
452 | 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo) | ||
453 | 57..76 'takes_...(&Foo)': () | ||
454 | 71..75 '&Foo': &Foo | ||
455 | 72..75 'Foo': Foo | ||
456 | 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo) | ||
457 | 82..102 'takes_...&&Foo)': () | ||
458 | 96..101 '&&Foo': &&Foo | ||
459 | 97..101 '&Foo': &Foo | ||
460 | 98..101 'Foo': Foo | ||
461 | 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo) | ||
462 | 108..129 'takes_...&&Foo)': () | ||
463 | 122..128 '&&&Foo': &&&Foo | ||
464 | 123..128 '&&Foo': &&Foo | ||
465 | 124..128 '&Foo': &Foo | ||
466 | 125..128 'Foo': Foo | ||
467 | "]], | ||
468 | ); | ||
469 | } | ||
470 | |||
471 | #[test] | ||
472 | fn coerce_autoderef_generic() { | ||
473 | check_infer_with_mismatches( | ||
474 | r" | ||
475 | struct Foo; | ||
476 | fn takes_ref<T>(x: &T) -> T { *x } | ||
477 | fn test() { | ||
478 | takes_ref(&Foo); | ||
479 | takes_ref(&&Foo); | ||
480 | takes_ref(&&&Foo); | ||
481 | } | ||
482 | ", | ||
483 | expect![[r" | ||
484 | 28..29 'x': &T | ||
485 | 40..46 '{ *x }': T | ||
486 | 42..44 '*x': T | ||
487 | 43..44 'x': &T | ||
488 | 57..126 '{ ...oo); }': () | ||
489 | 63..72 'takes_ref': fn takes_ref<Foo>(&Foo) -> Foo | ||
490 | 63..78 'takes_ref(&Foo)': Foo | ||
491 | 73..77 '&Foo': &Foo | ||
492 | 74..77 'Foo': Foo | ||
493 | 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo | ||
494 | 84..100 'takes_...&&Foo)': &Foo | ||
495 | 94..99 '&&Foo': &&Foo | ||
496 | 95..99 '&Foo': &Foo | ||
497 | 96..99 'Foo': Foo | ||
498 | 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo | ||
499 | 106..123 'takes_...&&Foo)': &&Foo | ||
500 | 116..122 '&&&Foo': &&&Foo | ||
501 | 117..122 '&&Foo': &&Foo | ||
502 | 118..122 '&Foo': &Foo | ||
503 | 119..122 'Foo': Foo | ||
504 | "]], | ||
505 | ); | ||
506 | } | ||
507 | |||
508 | #[test] | ||
509 | fn coerce_autoderef_block() { | ||
510 | check_infer_with_mismatches( | ||
511 | r#" | ||
512 | struct String {} | ||
513 | #[lang = "deref"] | ||
514 | trait Deref { type Target; } | ||
515 | impl Deref for String { type Target = str; } | ||
516 | fn takes_ref_str(x: &str) {} | ||
517 | fn returns_string() -> String { loop {} } | ||
518 | fn test() { | ||
519 | takes_ref_str(&{ returns_string() }); | ||
520 | } | ||
521 | "#, | ||
522 | expect![[r" | ||
523 | 126..127 'x': &str | ||
524 | 135..137 '{}': () | ||
525 | 168..179 '{ loop {} }': String | ||
526 | 170..177 'loop {}': ! | ||
527 | 175..177 '{}': () | ||
528 | 190..235 '{ ... }); }': () | ||
529 | 196..209 'takes_ref_str': fn takes_ref_str(&str) | ||
530 | 196..232 'takes_...g() })': () | ||
531 | 210..231 '&{ ret...ng() }': &String | ||
532 | 211..231 '{ retu...ng() }': String | ||
533 | 213..227 'returns_string': fn returns_string() -> String | ||
534 | 213..229 'return...ring()': String | ||
535 | "]], | ||
536 | ); | ||
537 | } | ||
538 | |||
539 | #[test] | ||
540 | fn closure_return_coerce() { | ||
541 | check_infer_with_mismatches( | ||
542 | r" | ||
543 | fn foo() { | ||
544 | let x = || { | ||
545 | if true { | ||
546 | return &1u32; | ||
547 | } | ||
548 | &&1u32 | ||
549 | }; | ||
550 | } | ||
551 | ", | ||
552 | expect![[r" | ||
553 | 9..105 '{ ... }; }': () | ||
554 | 19..20 'x': || -> &u32 | ||
555 | 23..102 '|| { ... }': || -> &u32 | ||
556 | 26..102 '{ ... }': &u32 | ||
557 | 36..81 'if tru... }': () | ||
558 | 39..43 'true': bool | ||
559 | 44..81 '{ ... }': () | ||
560 | 58..70 'return &1u32': ! | ||
561 | 65..70 '&1u32': &u32 | ||
562 | 66..70 '1u32': u32 | ||
563 | 90..96 '&&1u32': &&u32 | ||
564 | 91..96 '&1u32': &u32 | ||
565 | 92..96 '1u32': u32 | ||
566 | "]], | ||
567 | ); | ||
568 | } | ||
569 | |||
570 | #[test] | ||
571 | fn coerce_fn_item_to_fn_ptr() { | ||
572 | check_infer_with_mismatches( | ||
573 | r" | ||
574 | fn foo(x: u32) -> isize { 1 } | ||
575 | fn test() { | ||
576 | let f: fn(u32) -> isize = foo; | ||
577 | } | ||
578 | ", | ||
579 | expect![[r" | ||
580 | 7..8 'x': u32 | ||
581 | 24..29 '{ 1 }': isize | ||
582 | 26..27 '1': isize | ||
583 | 40..78 '{ ...foo; }': () | ||
584 | 50..51 'f': fn(u32) -> isize | ||
585 | 72..75 'foo': fn foo(u32) -> isize | ||
586 | "]], | ||
587 | ); | ||
588 | } | ||
589 | |||
590 | #[test] | ||
591 | fn coerce_fn_items_in_match_arms() { | ||
592 | mark::check!(coerce_fn_reification); | ||
593 | |||
594 | check_infer_with_mismatches( | ||
595 | r" | ||
596 | fn foo1(x: u32) -> isize { 1 } | ||
597 | fn foo2(x: u32) -> isize { 2 } | ||
598 | fn foo3(x: u32) -> isize { 3 } | ||
599 | fn test() { | ||
600 | let x = match 1 { | ||
601 | 1 => foo1, | ||
602 | 2 => foo2, | ||
603 | _ => foo3, | ||
604 | }; | ||
605 | } | ||
606 | ", | ||
607 | expect![[r" | ||
608 | 8..9 'x': u32 | ||
609 | 25..30 '{ 1 }': isize | ||
610 | 27..28 '1': isize | ||
611 | 39..40 'x': u32 | ||
612 | 56..61 '{ 2 }': isize | ||
613 | 58..59 '2': isize | ||
614 | 70..71 'x': u32 | ||
615 | 87..92 '{ 3 }': isize | ||
616 | 89..90 '3': isize | ||
617 | 103..192 '{ ... }; }': () | ||
618 | 113..114 'x': fn(u32) -> isize | ||
619 | 117..189 'match ... }': fn(u32) -> isize | ||
620 | 123..124 '1': i32 | ||
621 | 135..136 '1': i32 | ||
622 | 135..136 '1': i32 | ||
623 | 140..144 'foo1': fn foo1(u32) -> isize | ||
624 | 154..155 '2': i32 | ||
625 | 154..155 '2': i32 | ||
626 | 159..163 'foo2': fn foo2(u32) -> isize | ||
627 | 173..174 '_': i32 | ||
628 | 178..182 'foo3': fn foo3(u32) -> isize | ||
629 | "]], | ||
630 | ); | ||
631 | } | ||
632 | |||
633 | #[test] | ||
634 | fn coerce_closure_to_fn_ptr() { | ||
635 | check_infer_with_mismatches( | ||
636 | r" | ||
637 | fn test() { | ||
638 | let f: fn(u32) -> isize = |x| { 1 }; | ||
639 | } | ||
640 | ", | ||
641 | expect![[r" | ||
642 | 10..54 '{ ...1 }; }': () | ||
643 | 20..21 'f': fn(u32) -> isize | ||
644 | 42..51 '|x| { 1 }': |u32| -> isize | ||
645 | 43..44 'x': u32 | ||
646 | 46..51 '{ 1 }': isize | ||
647 | 48..49 '1': isize | ||
648 | "]], | ||
649 | ); | ||
650 | } | ||
651 | |||
652 | #[test] | ||
653 | fn coerce_placeholder_ref() { | ||
654 | // placeholders should unify, even behind references | ||
655 | check_infer_with_mismatches( | ||
656 | r" | ||
657 | struct S<T> { t: T } | ||
658 | impl<TT> S<TT> { | ||
659 | fn get(&self) -> &TT { | ||
660 | &self.t | ||
661 | } | ||
662 | } | ||
663 | ", | ||
664 | expect![[r" | ||
665 | 50..54 'self': &S<TT> | ||
666 | 63..86 '{ ... }': &TT | ||
667 | 73..80 '&self.t': &TT | ||
668 | 74..78 'self': &S<TT> | ||
669 | 74..80 'self.t': TT | ||
670 | "]], | ||
671 | ); | ||
672 | } | ||
673 | |||
674 | #[test] | ||
675 | fn coerce_unsize_array() { | ||
676 | check_infer_with_mismatches( | ||
677 | r#" | ||
678 | #[lang = "unsize"] | ||
679 | pub trait Unsize<T> {} | ||
680 | #[lang = "coerce_unsized"] | ||
681 | pub trait CoerceUnsized<T> {} | ||
682 | |||
683 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
684 | |||
685 | fn test() { | ||
686 | let f: &[usize] = &[1, 2, 3]; | ||
687 | } | ||
688 | "#, | ||
689 | expect![[r" | ||
690 | 161..198 '{ ... 3]; }': () | ||
691 | 171..172 'f': &[usize] | ||
692 | 185..195 '&[1, 2, 3]': &[usize; _] | ||
693 | 186..195 '[1, 2, 3]': [usize; _] | ||
694 | 187..188 '1': usize | ||
695 | 190..191 '2': usize | ||
696 | 193..194 '3': usize | ||
697 | "]], | ||
698 | ); | ||
699 | } | ||
700 | |||
701 | #[test] | ||
702 | fn coerce_unsize_trait_object_simple() { | ||
703 | check_infer_with_mismatches( | ||
704 | r#" | ||
705 | #[lang = "sized"] | ||
706 | pub trait Sized {} | ||
707 | #[lang = "unsize"] | ||
708 | pub trait Unsize<T> {} | ||
709 | #[lang = "coerce_unsized"] | ||
710 | pub trait CoerceUnsized<T> {} | ||
711 | |||
712 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
713 | |||
714 | trait Foo<T, U> {} | ||
715 | trait Bar<U, T, X>: Foo<T, U> {} | ||
716 | trait Baz<T, X>: Bar<usize, T, X> {} | ||
717 | |||
718 | struct S<T, X>; | ||
719 | impl<T, X> Foo<T, usize> for S<T, X> {} | ||
720 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | ||
721 | impl<T, X> Baz<T, X> for S<T, X> {} | ||
722 | |||
723 | fn test() { | ||
724 | let obj: &dyn Baz<i8, i16> = &S; | ||
725 | let obj: &dyn Bar<_, i8, i16> = &S; | ||
726 | let obj: &dyn Foo<i8, _> = &S; | ||
727 | } | ||
728 | "#, | ||
729 | expect![[r" | ||
730 | 424..539 '{ ... &S; }': () | ||
731 | 434..437 'obj': &dyn Baz<i8, i16> | ||
732 | 459..461 '&S': &S<i8, i16> | ||
733 | 460..461 'S': S<i8, i16> | ||
734 | 471..474 'obj': &dyn Bar<usize, i8, i16> | ||
735 | 499..501 '&S': &S<i8, i16> | ||
736 | 500..501 'S': S<i8, i16> | ||
737 | 511..514 'obj': &dyn Foo<i8, usize> | ||
738 | 534..536 '&S': &S<i8, {unknown}> | ||
739 | 535..536 'S': S<i8, {unknown}> | ||
740 | "]], | ||
741 | ); | ||
742 | } | ||
743 | |||
744 | #[test] | ||
745 | // The rust reference says this should be possible, but rustc doesn't implement | ||
746 | // it. We used to support it, but Chalk doesn't. | ||
747 | #[ignore] | ||
748 | fn coerce_unsize_trait_object_to_trait_object() { | ||
749 | check_infer_with_mismatches( | ||
750 | r#" | ||
751 | #[lang = "sized"] | ||
752 | pub trait Sized {} | ||
753 | #[lang = "unsize"] | ||
754 | pub trait Unsize<T> {} | ||
755 | #[lang = "coerce_unsized"] | ||
756 | pub trait CoerceUnsized<T> {} | ||
757 | |||
758 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
759 | |||
760 | trait Foo<T, U> {} | ||
761 | trait Bar<U, T, X>: Foo<T, U> {} | ||
762 | trait Baz<T, X>: Bar<usize, T, X> {} | ||
763 | |||
764 | struct S<T, X>; | ||
765 | impl<T, X> Foo<T, usize> for S<T, X> {} | ||
766 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | ||
767 | impl<T, X> Baz<T, X> for S<T, X> {} | ||
768 | |||
769 | fn test() { | ||
770 | let obj: &dyn Baz<i8, i16> = &S; | ||
771 | let obj: &dyn Bar<_, _, _> = obj; | ||
772 | let obj: &dyn Foo<_, _> = obj; | ||
773 | let obj2: &dyn Baz<i8, i16> = &S; | ||
774 | let _: &dyn Foo<_, _> = obj2; | ||
775 | } | ||
776 | "#, | ||
777 | expect![[r" | ||
778 | 424..609 '{ ...bj2; }': () | ||
779 | 434..437 'obj': &dyn Baz<i8, i16> | ||
780 | 459..461 '&S': &S<i8, i16> | ||
781 | 460..461 'S': S<i8, i16> | ||
782 | 471..474 'obj': &dyn Bar<usize, i8, i16> | ||
783 | 496..499 'obj': &dyn Baz<i8, i16> | ||
784 | 509..512 'obj': &dyn Foo<i8, usize> | ||
785 | 531..534 'obj': &dyn Bar<usize, i8, i16> | ||
786 | 544..548 'obj2': &dyn Baz<i8, i16> | ||
787 | 570..572 '&S': &S<i8, i16> | ||
788 | 571..572 'S': S<i8, i16> | ||
789 | 582..583 '_': &dyn Foo<i8, usize> | ||
790 | 602..606 'obj2': &dyn Baz<i8, i16> | ||
791 | "]], | ||
792 | ); | ||
793 | } | ||
794 | |||
795 | #[test] | ||
796 | fn coerce_unsize_super_trait_cycle() { | ||
797 | check_infer_with_mismatches( | ||
798 | r#" | ||
799 | #[lang = "sized"] | ||
800 | pub trait Sized {} | ||
801 | #[lang = "unsize"] | ||
802 | pub trait Unsize<T> {} | ||
803 | #[lang = "coerce_unsized"] | ||
804 | pub trait CoerceUnsized<T> {} | ||
805 | |||
806 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
807 | |||
808 | trait A {} | ||
809 | trait B: C + A {} | ||
810 | trait C: B {} | ||
811 | trait D: C | ||
812 | |||
813 | struct S; | ||
814 | impl A for S {} | ||
815 | impl B for S {} | ||
816 | impl C for S {} | ||
817 | impl D for S {} | ||
818 | |||
819 | fn test() { | ||
820 | let obj: &dyn D = &S; | ||
821 | let obj: &dyn A = &S; | ||
822 | } | ||
823 | "#, | ||
824 | expect![[r" | ||
825 | 328..383 '{ ... &S; }': () | ||
826 | 338..341 'obj': &dyn D | ||
827 | 352..354 '&S': &S | ||
828 | 353..354 'S': S | ||
829 | 364..367 'obj': &dyn A | ||
830 | 378..380 '&S': &S | ||
831 | 379..380 'S': S | ||
832 | "]], | ||
833 | ); | ||
834 | } | ||
835 | |||
836 | #[ignore] | ||
837 | #[test] | ||
838 | fn coerce_unsize_generic() { | ||
839 | // FIXME: Implement this | ||
840 | // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions | ||
841 | check_infer_with_mismatches( | ||
842 | r#" | ||
843 | #[lang = "unsize"] | ||
844 | pub trait Unsize<T> {} | ||
845 | #[lang = "coerce_unsized"] | ||
846 | pub trait CoerceUnsized<T> {} | ||
847 | |||
848 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
849 | |||
850 | struct Foo<T> { t: T }; | ||
851 | struct Bar<T>(Foo<T>); | ||
852 | |||
853 | fn test() { | ||
854 | let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; | ||
855 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); | ||
856 | } | ||
857 | "#, | ||
858 | expect![[r" | ||
859 | "]], | ||
860 | ); | ||
861 | } | ||
diff --git a/crates/hir_ty/src/tests/display_source_code.rs b/crates/hir_ty/src/tests/display_source_code.rs new file mode 100644 index 000000000..b502135d8 --- /dev/null +++ b/crates/hir_ty/src/tests/display_source_code.rs | |||
@@ -0,0 +1,41 @@ | |||
1 | use super::check_types_source_code; | ||
2 | |||
3 | #[test] | ||
4 | fn qualify_path_to_submodule() { | ||
5 | check_types_source_code( | ||
6 | r#" | ||
7 | mod foo { | ||
8 | pub struct Foo; | ||
9 | } | ||
10 | |||
11 | fn bar() { | ||
12 | let foo: foo::Foo = foo::Foo; | ||
13 | foo | ||
14 | } //^ foo::Foo | ||
15 | |||
16 | "#, | ||
17 | ); | ||
18 | } | ||
19 | |||
20 | #[test] | ||
21 | fn omit_default_type_parameters() { | ||
22 | check_types_source_code( | ||
23 | r#" | ||
24 | struct Foo<T = u8> { t: T } | ||
25 | fn main() { | ||
26 | let foo = Foo { t: 5u8 }; | ||
27 | foo; | ||
28 | } //^ Foo | ||
29 | "#, | ||
30 | ); | ||
31 | |||
32 | check_types_source_code( | ||
33 | r#" | ||
34 | struct Foo<K, T = u8> { k: K, t: T } | ||
35 | fn main() { | ||
36 | let foo = Foo { k: 400, t: 5u8 }; | ||
37 | foo; | ||
38 | } //^ Foo<i32> | ||
39 | "#, | ||
40 | ); | ||
41 | } | ||
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs new file mode 100644 index 000000000..d887c7a79 --- /dev/null +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -0,0 +1,787 @@ | |||
1 | use std::fs; | ||
2 | |||
3 | use expect::expect; | ||
4 | use test_utils::project_dir; | ||
5 | |||
6 | use super::{check_infer, check_types}; | ||
7 | |||
8 | #[test] | ||
9 | fn cfg_impl_def() { | ||
10 | check_types( | ||
11 | r#" | ||
12 | //- /main.rs crate:main deps:foo cfg:test | ||
13 | use foo::S as T; | ||
14 | struct S; | ||
15 | |||
16 | #[cfg(test)] | ||
17 | impl S { | ||
18 | fn foo1(&self) -> i32 { 0 } | ||
19 | } | ||
20 | |||
21 | #[cfg(not(test))] | ||
22 | impl S { | ||
23 | fn foo2(&self) -> i32 { 0 } | ||
24 | } | ||
25 | |||
26 | fn test() { | ||
27 | let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4()); | ||
28 | t; | ||
29 | } //^ (i32, {unknown}, i32, {unknown}) | ||
30 | |||
31 | //- /foo.rs crate:foo | ||
32 | struct S; | ||
33 | |||
34 | #[cfg(not(test))] | ||
35 | impl S { | ||
36 | fn foo3(&self) -> i32 { 0 } | ||
37 | } | ||
38 | |||
39 | #[cfg(test)] | ||
40 | impl S { | ||
41 | fn foo4(&self) -> i32 { 0 } | ||
42 | } | ||
43 | "#, | ||
44 | ); | ||
45 | } | ||
46 | |||
47 | #[test] | ||
48 | fn infer_macros_expanded() { | ||
49 | check_infer( | ||
50 | r#" | ||
51 | struct Foo(Vec<i32>); | ||
52 | |||
53 | macro_rules! foo { | ||
54 | ($($item:expr),*) => { | ||
55 | { | ||
56 | Foo(vec![$($item,)*]) | ||
57 | } | ||
58 | }; | ||
59 | } | ||
60 | |||
61 | fn main() { | ||
62 | let x = foo!(1,2); | ||
63 | } | ||
64 | "#, | ||
65 | expect![[r#" | ||
66 | !0..17 '{Foo(v...,2,])}': Foo | ||
67 | !1..4 'Foo': Foo({unknown}) -> Foo | ||
68 | !1..16 'Foo(vec![1,2,])': Foo | ||
69 | !5..15 'vec![1,2,]': {unknown} | ||
70 | 155..181 '{ ...,2); }': () | ||
71 | 165..166 'x': Foo | ||
72 | "#]], | ||
73 | ); | ||
74 | } | ||
75 | |||
76 | #[test] | ||
77 | fn infer_legacy_textual_scoped_macros_expanded() { | ||
78 | check_infer( | ||
79 | r#" | ||
80 | struct Foo(Vec<i32>); | ||
81 | |||
82 | #[macro_use] | ||
83 | mod m { | ||
84 | macro_rules! foo { | ||
85 | ($($item:expr),*) => { | ||
86 | { | ||
87 | Foo(vec![$($item,)*]) | ||
88 | } | ||
89 | }; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | fn main() { | ||
94 | let x = foo!(1,2); | ||
95 | let y = crate::foo!(1,2); | ||
96 | } | ||
97 | "#, | ||
98 | expect![[r#" | ||
99 | !0..17 '{Foo(v...,2,])}': Foo | ||
100 | !1..4 'Foo': Foo({unknown}) -> Foo | ||
101 | !1..16 'Foo(vec![1,2,])': Foo | ||
102 | !5..15 'vec![1,2,]': {unknown} | ||
103 | 194..250 '{ ...,2); }': () | ||
104 | 204..205 'x': Foo | ||
105 | 227..228 'y': {unknown} | ||
106 | 231..247 'crate:...!(1,2)': {unknown} | ||
107 | "#]], | ||
108 | ); | ||
109 | } | ||
110 | |||
111 | #[test] | ||
112 | fn infer_path_qualified_macros_expanded() { | ||
113 | check_infer( | ||
114 | r#" | ||
115 | #[macro_export] | ||
116 | macro_rules! foo { | ||
117 | () => { 42i32 } | ||
118 | } | ||
119 | |||
120 | mod m { | ||
121 | pub use super::foo as bar; | ||
122 | } | ||
123 | |||
124 | fn main() { | ||
125 | let x = crate::foo!(); | ||
126 | let y = m::bar!(); | ||
127 | } | ||
128 | "#, | ||
129 | expect![[r#" | ||
130 | !0..5 '42i32': i32 | ||
131 | !0..5 '42i32': i32 | ||
132 | 110..163 '{ ...!(); }': () | ||
133 | 120..121 'x': i32 | ||
134 | 147..148 'y': i32 | ||
135 | "#]], | ||
136 | ); | ||
137 | } | ||
138 | |||
139 | #[test] | ||
140 | fn expr_macro_expanded_in_various_places() { | ||
141 | check_infer( | ||
142 | r#" | ||
143 | macro_rules! spam { | ||
144 | () => (1isize); | ||
145 | } | ||
146 | |||
147 | fn spam() { | ||
148 | spam!(); | ||
149 | (spam!()); | ||
150 | spam!().spam(spam!()); | ||
151 | for _ in spam!() {} | ||
152 | || spam!(); | ||
153 | while spam!() {} | ||
154 | break spam!(); | ||
155 | return spam!(); | ||
156 | match spam!() { | ||
157 | _ if spam!() => spam!(), | ||
158 | } | ||
159 | spam!()(spam!()); | ||
160 | Spam { spam: spam!() }; | ||
161 | spam!()[spam!()]; | ||
162 | await spam!(); | ||
163 | spam!() as usize; | ||
164 | &spam!(); | ||
165 | -spam!(); | ||
166 | spam!()..spam!(); | ||
167 | spam!() + spam!(); | ||
168 | } | ||
169 | "#, | ||
170 | expect![[r#" | ||
171 | !0..6 '1isize': isize | ||
172 | !0..6 '1isize': isize | ||
173 | !0..6 '1isize': isize | ||
174 | !0..6 '1isize': isize | ||
175 | !0..6 '1isize': isize | ||
176 | !0..6 '1isize': isize | ||
177 | !0..6 '1isize': isize | ||
178 | !0..6 '1isize': isize | ||
179 | !0..6 '1isize': isize | ||
180 | !0..6 '1isize': isize | ||
181 | !0..6 '1isize': isize | ||
182 | !0..6 '1isize': isize | ||
183 | !0..6 '1isize': isize | ||
184 | !0..6 '1isize': isize | ||
185 | !0..6 '1isize': isize | ||
186 | !0..6 '1isize': isize | ||
187 | !0..6 '1isize': isize | ||
188 | !0..6 '1isize': isize | ||
189 | !0..6 '1isize': isize | ||
190 | !0..6 '1isize': isize | ||
191 | !0..6 '1isize': isize | ||
192 | !0..6 '1isize': isize | ||
193 | !0..6 '1isize': isize | ||
194 | !0..6 '1isize': isize | ||
195 | !0..6 '1isize': isize | ||
196 | 53..456 '{ ...!(); }': () | ||
197 | 87..108 'spam!(...am!())': {unknown} | ||
198 | 114..133 'for _ ...!() {}': () | ||
199 | 118..119 '_': {unknown} | ||
200 | 131..133 '{}': () | ||
201 | 138..148 '|| spam!()': || -> isize | ||
202 | 154..170 'while ...!() {}': () | ||
203 | 168..170 '{}': () | ||
204 | 175..188 'break spam!()': ! | ||
205 | 194..208 'return spam!()': ! | ||
206 | 214..268 'match ... }': isize | ||
207 | 238..239 '_': isize | ||
208 | 273..289 'spam!(...am!())': {unknown} | ||
209 | 295..317 'Spam {...m!() }': {unknown} | ||
210 | 323..339 'spam!(...am!()]': {unknown} | ||
211 | 364..380 'spam!(... usize': usize | ||
212 | 386..394 '&spam!()': &isize | ||
213 | 400..408 '-spam!()': isize | ||
214 | 414..430 'spam!(...pam!()': {unknown} | ||
215 | 436..453 'spam!(...pam!()': isize | ||
216 | "#]], | ||
217 | ); | ||
218 | } | ||
219 | |||
220 | #[test] | ||
221 | fn infer_type_value_macro_having_same_name() { | ||
222 | check_infer( | ||
223 | r#" | ||
224 | #[macro_export] | ||
225 | macro_rules! foo { | ||
226 | () => { | ||
227 | mod foo { | ||
228 | pub use super::foo; | ||
229 | } | ||
230 | }; | ||
231 | ($x:tt) => { | ||
232 | $x | ||
233 | }; | ||
234 | } | ||
235 | |||
236 | foo!(); | ||
237 | |||
238 | fn foo() { | ||
239 | let foo = foo::foo!(42i32); | ||
240 | } | ||
241 | "#, | ||
242 | expect![[r#" | ||
243 | !0..5 '42i32': i32 | ||
244 | 170..205 '{ ...32); }': () | ||
245 | 180..183 'foo': i32 | ||
246 | "#]], | ||
247 | ); | ||
248 | } | ||
249 | |||
250 | #[test] | ||
251 | fn processes_impls_generated_by_macros() { | ||
252 | check_types( | ||
253 | r#" | ||
254 | macro_rules! m { | ||
255 | ($ident:ident) => (impl Trait for $ident {}) | ||
256 | } | ||
257 | trait Trait { fn foo(self) -> u128 {} } | ||
258 | struct S; | ||
259 | m!(S); | ||
260 | fn test() { S.foo(); } | ||
261 | //^ u128 | ||
262 | "#, | ||
263 | ); | ||
264 | } | ||
265 | |||
266 | #[test] | ||
267 | fn infer_assoc_items_generated_by_macros() { | ||
268 | check_types( | ||
269 | r#" | ||
270 | macro_rules! m { | ||
271 | () => (fn foo(&self) -> u128 {0}) | ||
272 | } | ||
273 | struct S; | ||
274 | impl S { | ||
275 | m!(); | ||
276 | } | ||
277 | |||
278 | fn test() { S.foo(); } | ||
279 | //^ u128 | ||
280 | "#, | ||
281 | ); | ||
282 | } | ||
283 | |||
284 | #[test] | ||
285 | fn infer_assoc_items_generated_by_macros_chain() { | ||
286 | check_types( | ||
287 | r#" | ||
288 | macro_rules! m_inner { | ||
289 | () => {fn foo(&self) -> u128 {0}} | ||
290 | } | ||
291 | macro_rules! m { | ||
292 | () => {m_inner!();} | ||
293 | } | ||
294 | |||
295 | struct S; | ||
296 | impl S { | ||
297 | m!(); | ||
298 | } | ||
299 | |||
300 | fn test() { S.foo(); } | ||
301 | //^ u128 | ||
302 | "#, | ||
303 | ); | ||
304 | } | ||
305 | |||
306 | #[test] | ||
307 | fn infer_macro_with_dollar_crate_is_correct_in_expr() { | ||
308 | check_types( | ||
309 | r#" | ||
310 | //- /main.rs crate:main deps:foo | ||
311 | fn test() { | ||
312 | let x = (foo::foo!(1), foo::foo!(2)); | ||
313 | x; | ||
314 | } //^ (i32, usize) | ||
315 | |||
316 | //- /lib.rs crate:foo | ||
317 | #[macro_export] | ||
318 | macro_rules! foo { | ||
319 | (1) => { $crate::bar!() }; | ||
320 | (2) => { 1 + $crate::baz() }; | ||
321 | } | ||
322 | |||
323 | #[macro_export] | ||
324 | macro_rules! bar { | ||
325 | () => { 42 } | ||
326 | } | ||
327 | |||
328 | pub fn baz() -> usize { 31usize } | ||
329 | "#, | ||
330 | ); | ||
331 | } | ||
332 | |||
333 | #[test] | ||
334 | fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { | ||
335 | check_types( | ||
336 | r#" | ||
337 | //- /main.rs crate:main deps:foo | ||
338 | use foo::Trait; | ||
339 | |||
340 | fn test() { | ||
341 | let msg = foo::Message(foo::MessageRef); | ||
342 | let r = msg.deref(); | ||
343 | r; | ||
344 | //^ &MessageRef | ||
345 | } | ||
346 | |||
347 | //- /lib.rs crate:foo | ||
348 | pub struct MessageRef; | ||
349 | pub struct Message(MessageRef); | ||
350 | |||
351 | pub trait Trait { | ||
352 | type Target; | ||
353 | fn deref(&self) -> &Self::Target; | ||
354 | } | ||
355 | |||
356 | #[macro_export] | ||
357 | macro_rules! expand { | ||
358 | () => { | ||
359 | impl Trait for Message { | ||
360 | type Target = $crate::MessageRef; | ||
361 | fn deref(&self) -> &Self::Target { | ||
362 | &self.0 | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | } | ||
367 | |||
368 | expand!(); | ||
369 | "#, | ||
370 | ); | ||
371 | } | ||
372 | |||
373 | #[test] | ||
374 | fn infer_type_value_non_legacy_macro_use_as() { | ||
375 | check_infer( | ||
376 | r#" | ||
377 | mod m { | ||
378 | macro_rules! _foo { | ||
379 | ($x:ident) => { type $x = u64; } | ||
380 | } | ||
381 | pub(crate) use _foo as foo; | ||
382 | } | ||
383 | |||
384 | m::foo!(foo); | ||
385 | use foo as bar; | ||
386 | fn f() -> bar { 0 } | ||
387 | fn main() { | ||
388 | let _a = f(); | ||
389 | } | ||
390 | "#, | ||
391 | expect![[r#" | ||
392 | 158..163 '{ 0 }': u64 | ||
393 | 160..161 '0': u64 | ||
394 | 174..196 '{ ...f(); }': () | ||
395 | 184..186 '_a': u64 | ||
396 | 190..191 'f': fn f() -> u64 | ||
397 | 190..193 'f()': u64 | ||
398 | "#]], | ||
399 | ); | ||
400 | } | ||
401 | |||
402 | #[test] | ||
403 | fn infer_local_macro() { | ||
404 | check_infer( | ||
405 | r#" | ||
406 | fn main() { | ||
407 | macro_rules! foo { | ||
408 | () => { 1usize } | ||
409 | } | ||
410 | let _a = foo!(); | ||
411 | } | ||
412 | "#, | ||
413 | expect![[r#" | ||
414 | !0..6 '1usize': usize | ||
415 | 10..89 '{ ...!(); }': () | ||
416 | 16..65 'macro_... }': {unknown} | ||
417 | 74..76 '_a': usize | ||
418 | "#]], | ||
419 | ); | ||
420 | } | ||
421 | |||
422 | #[test] | ||
423 | fn infer_local_inner_macros() { | ||
424 | check_types( | ||
425 | r#" | ||
426 | //- /main.rs crate:main deps:foo | ||
427 | fn test() { | ||
428 | let x = foo::foo!(1); | ||
429 | x; | ||
430 | } //^ i32 | ||
431 | |||
432 | //- /lib.rs crate:foo | ||
433 | #[macro_export(local_inner_macros)] | ||
434 | macro_rules! foo { | ||
435 | (1) => { bar!() }; | ||
436 | } | ||
437 | |||
438 | #[macro_export] | ||
439 | macro_rules! bar { | ||
440 | () => { 42 } | ||
441 | } | ||
442 | |||
443 | "#, | ||
444 | ); | ||
445 | } | ||
446 | |||
447 | #[test] | ||
448 | fn infer_builtin_macros_line() { | ||
449 | check_infer( | ||
450 | r#" | ||
451 | #[rustc_builtin_macro] | ||
452 | macro_rules! line {() => {}} | ||
453 | |||
454 | fn main() { | ||
455 | let x = line!(); | ||
456 | } | ||
457 | "#, | ||
458 | expect![[r#" | ||
459 | !0..1 '0': i32 | ||
460 | 63..87 '{ ...!(); }': () | ||
461 | 73..74 'x': i32 | ||
462 | "#]], | ||
463 | ); | ||
464 | } | ||
465 | |||
466 | #[test] | ||
467 | fn infer_builtin_macros_file() { | ||
468 | check_infer( | ||
469 | r#" | ||
470 | #[rustc_builtin_macro] | ||
471 | macro_rules! file {() => {}} | ||
472 | |||
473 | fn main() { | ||
474 | let x = file!(); | ||
475 | } | ||
476 | "#, | ||
477 | expect![[r#" | ||
478 | !0..2 '""': &str | ||
479 | 63..87 '{ ...!(); }': () | ||
480 | 73..74 'x': &str | ||
481 | "#]], | ||
482 | ); | ||
483 | } | ||
484 | |||
485 | #[test] | ||
486 | fn infer_builtin_macros_column() { | ||
487 | check_infer( | ||
488 | r#" | ||
489 | #[rustc_builtin_macro] | ||
490 | macro_rules! column {() => {}} | ||
491 | |||
492 | fn main() { | ||
493 | let x = column!(); | ||
494 | } | ||
495 | "#, | ||
496 | expect![[r#" | ||
497 | !0..1 '0': i32 | ||
498 | 65..91 '{ ...!(); }': () | ||
499 | 75..76 'x': i32 | ||
500 | "#]], | ||
501 | ); | ||
502 | } | ||
503 | |||
504 | #[test] | ||
505 | fn infer_builtin_macros_concat() { | ||
506 | check_infer( | ||
507 | r#" | ||
508 | #[rustc_builtin_macro] | ||
509 | macro_rules! concat {() => {}} | ||
510 | |||
511 | fn main() { | ||
512 | let x = concat!("hello", concat!("world", "!")); | ||
513 | } | ||
514 | "#, | ||
515 | expect![[r#" | ||
516 | !0..13 '"helloworld!"': &str | ||
517 | 65..121 '{ ...")); }': () | ||
518 | 75..76 'x': &str | ||
519 | "#]], | ||
520 | ); | ||
521 | } | ||
522 | |||
523 | #[test] | ||
524 | fn infer_builtin_macros_include() { | ||
525 | check_types( | ||
526 | r#" | ||
527 | //- /main.rs | ||
528 | #[rustc_builtin_macro] | ||
529 | macro_rules! include {() => {}} | ||
530 | |||
531 | include!("foo.rs"); | ||
532 | |||
533 | fn main() { | ||
534 | bar(); | ||
535 | } //^ u32 | ||
536 | |||
537 | //- /foo.rs | ||
538 | fn bar() -> u32 {0} | ||
539 | "#, | ||
540 | ); | ||
541 | } | ||
542 | |||
543 | #[test] | ||
544 | #[ignore] | ||
545 | fn include_accidentally_quadratic() { | ||
546 | let file = project_dir().join("crates/syntax/test_data/accidentally_quadratic"); | ||
547 | let big_file = fs::read_to_string(file).unwrap(); | ||
548 | let big_file = vec![big_file; 10].join("\n"); | ||
549 | |||
550 | let fixture = r#" | ||
551 | //- /main.rs | ||
552 | #[rustc_builtin_macro] | ||
553 | macro_rules! include {() => {}} | ||
554 | |||
555 | include!("foo.rs"); | ||
556 | |||
557 | fn main() { | ||
558 | RegisterBlock { }; | ||
559 | //^ RegisterBlock | ||
560 | } | ||
561 | "#; | ||
562 | let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file); | ||
563 | check_types(&fixture); | ||
564 | } | ||
565 | |||
566 | #[test] | ||
567 | fn infer_builtin_macros_include_concat() { | ||
568 | check_types( | ||
569 | r#" | ||
570 | //- /main.rs | ||
571 | #[rustc_builtin_macro] | ||
572 | macro_rules! include {() => {}} | ||
573 | |||
574 | #[rustc_builtin_macro] | ||
575 | macro_rules! concat {() => {}} | ||
576 | |||
577 | include!(concat!("f", "oo.rs")); | ||
578 | |||
579 | fn main() { | ||
580 | bar(); | ||
581 | } //^ u32 | ||
582 | |||
583 | //- /foo.rs | ||
584 | fn bar() -> u32 {0} | ||
585 | "#, | ||
586 | ); | ||
587 | } | ||
588 | |||
589 | #[test] | ||
590 | fn infer_builtin_macros_include_concat_with_bad_env_should_failed() { | ||
591 | check_types( | ||
592 | r#" | ||
593 | //- /main.rs | ||
594 | #[rustc_builtin_macro] | ||
595 | macro_rules! include {() => {}} | ||
596 | |||
597 | #[rustc_builtin_macro] | ||
598 | macro_rules! concat {() => {}} | ||
599 | |||
600 | #[rustc_builtin_macro] | ||
601 | macro_rules! env {() => {}} | ||
602 | |||
603 | include!(concat!(env!("OUT_DIR"), "/foo.rs")); | ||
604 | |||
605 | fn main() { | ||
606 | bar(); | ||
607 | } //^ {unknown} | ||
608 | |||
609 | //- /foo.rs | ||
610 | fn bar() -> u32 {0} | ||
611 | "#, | ||
612 | ); | ||
613 | } | ||
614 | |||
615 | #[test] | ||
616 | fn infer_builtin_macros_include_itself_should_failed() { | ||
617 | check_types( | ||
618 | r#" | ||
619 | #[rustc_builtin_macro] | ||
620 | macro_rules! include {() => {}} | ||
621 | |||
622 | include!("main.rs"); | ||
623 | |||
624 | fn main() { | ||
625 | 0 | ||
626 | } //^ i32 | ||
627 | "#, | ||
628 | ); | ||
629 | } | ||
630 | |||
631 | #[test] | ||
632 | fn infer_builtin_macros_concat_with_lazy() { | ||
633 | check_infer( | ||
634 | r#" | ||
635 | macro_rules! hello {() => {"hello"}} | ||
636 | |||
637 | #[rustc_builtin_macro] | ||
638 | macro_rules! concat {() => {}} | ||
639 | |||
640 | fn main() { | ||
641 | let x = concat!(hello!(), concat!("world", "!")); | ||
642 | } | ||
643 | "#, | ||
644 | expect![[r#" | ||
645 | !0..13 '"helloworld!"': &str | ||
646 | 103..160 '{ ...")); }': () | ||
647 | 113..114 'x': &str | ||
648 | "#]], | ||
649 | ); | ||
650 | } | ||
651 | |||
652 | #[test] | ||
653 | fn infer_builtin_macros_env() { | ||
654 | check_infer( | ||
655 | r#" | ||
656 | //- /main.rs env:foo=bar | ||
657 | #[rustc_builtin_macro] | ||
658 | macro_rules! env {() => {}} | ||
659 | |||
660 | fn main() { | ||
661 | let x = env!("foo"); | ||
662 | } | ||
663 | "#, | ||
664 | expect![[r#" | ||
665 | !0..22 '"__RA_...TED__"': &str | ||
666 | 62..90 '{ ...o"); }': () | ||
667 | 72..73 'x': &str | ||
668 | "#]], | ||
669 | ); | ||
670 | } | ||
671 | |||
672 | #[test] | ||
673 | fn infer_derive_clone_simple() { | ||
674 | check_types( | ||
675 | r#" | ||
676 | //- /main.rs crate:main deps:core | ||
677 | #[derive(Clone)] | ||
678 | struct S; | ||
679 | fn test() { | ||
680 | S.clone(); | ||
681 | } //^ S | ||
682 | |||
683 | //- /lib.rs crate:core | ||
684 | #[prelude_import] | ||
685 | use clone::*; | ||
686 | mod clone { | ||
687 | trait Clone { | ||
688 | fn clone(&self) -> Self; | ||
689 | } | ||
690 | } | ||
691 | "#, | ||
692 | ); | ||
693 | } | ||
694 | |||
695 | #[test] | ||
696 | fn infer_derive_clone_in_core() { | ||
697 | check_types( | ||
698 | r#" | ||
699 | //- /lib.rs crate:core | ||
700 | #[prelude_import] | ||
701 | use clone::*; | ||
702 | mod clone { | ||
703 | trait Clone { | ||
704 | fn clone(&self) -> Self; | ||
705 | } | ||
706 | } | ||
707 | #[derive(Clone)] | ||
708 | pub struct S; | ||
709 | |||
710 | //- /main.rs crate:main deps:core | ||
711 | use core::S; | ||
712 | fn test() { | ||
713 | S.clone(); | ||
714 | } //^ S | ||
715 | "#, | ||
716 | ); | ||
717 | } | ||
718 | |||
719 | #[test] | ||
720 | fn infer_derive_clone_with_params() { | ||
721 | check_types( | ||
722 | r#" | ||
723 | //- /main.rs crate:main deps:core | ||
724 | #[derive(Clone)] | ||
725 | struct S; | ||
726 | #[derive(Clone)] | ||
727 | struct Wrapper<T>(T); | ||
728 | struct NonClone; | ||
729 | fn test() { | ||
730 | (Wrapper(S).clone(), Wrapper(NonClone).clone()); | ||
731 | //^ (Wrapper<S>, {unknown}) | ||
732 | } | ||
733 | |||
734 | //- /lib.rs crate:core | ||
735 | #[prelude_import] | ||
736 | use clone::*; | ||
737 | mod clone { | ||
738 | trait Clone { | ||
739 | fn clone(&self) -> Self; | ||
740 | } | ||
741 | } | ||
742 | "#, | ||
743 | ); | ||
744 | } | ||
745 | |||
746 | #[test] | ||
747 | fn infer_custom_derive_simple() { | ||
748 | // FIXME: this test current now do nothing | ||
749 | check_types( | ||
750 | r#" | ||
751 | //- /main.rs crate:main | ||
752 | use foo::Foo; | ||
753 | |||
754 | #[derive(Foo)] | ||
755 | struct S{} | ||
756 | |||
757 | fn test() { | ||
758 | S{}; | ||
759 | } //^ S | ||
760 | "#, | ||
761 | ); | ||
762 | } | ||
763 | |||
764 | #[test] | ||
765 | fn macro_in_arm() { | ||
766 | check_infer( | ||
767 | r#" | ||
768 | macro_rules! unit { | ||
769 | () => { () }; | ||
770 | } | ||
771 | |||
772 | fn main() { | ||
773 | let x = match () { | ||
774 | unit!() => 92u32, | ||
775 | }; | ||
776 | } | ||
777 | "#, | ||
778 | expect![[r#" | ||
779 | 51..110 '{ ... }; }': () | ||
780 | 61..62 'x': u32 | ||
781 | 65..107 'match ... }': u32 | ||
782 | 71..73 '()': () | ||
783 | 84..91 'unit!()': () | ||
784 | 95..100 '92u32': u32 | ||
785 | "#]], | ||
786 | ); | ||
787 | } | ||
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs new file mode 100644 index 000000000..fa68355aa --- /dev/null +++ b/crates/hir_ty/src/tests/method_resolution.rs | |||
@@ -0,0 +1,1053 @@ | |||
1 | use expect::expect; | ||
2 | |||
3 | use super::{check_infer, check_types}; | ||
4 | |||
5 | #[test] | ||
6 | fn infer_slice_method() { | ||
7 | check_infer( | ||
8 | r#" | ||
9 | #[lang = "slice"] | ||
10 | impl<T> [T] { | ||
11 | fn foo(&self) -> T { | ||
12 | loop {} | ||
13 | } | ||
14 | } | ||
15 | |||
16 | #[lang = "slice_alloc"] | ||
17 | impl<T> [T] {} | ||
18 | |||
19 | fn test(x: &[u8]) { | ||
20 | <[_]>::foo(x); | ||
21 | } | ||
22 | "#, | ||
23 | expect![[r#" | ||
24 | 44..48 'self': &[T] | ||
25 | 55..78 '{ ... }': T | ||
26 | 65..72 'loop {}': ! | ||
27 | 70..72 '{}': () | ||
28 | 130..131 'x': &[u8] | ||
29 | 140..162 '{ ...(x); }': () | ||
30 | 146..156 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8 | ||
31 | 146..159 '<[_]>::foo(x)': u8 | ||
32 | 157..158 'x': &[u8] | ||
33 | "#]], | ||
34 | ); | ||
35 | } | ||
36 | |||
37 | #[test] | ||
38 | fn infer_associated_method_struct() { | ||
39 | check_infer( | ||
40 | r#" | ||
41 | struct A { x: u32 } | ||
42 | |||
43 | impl A { | ||
44 | fn new() -> A { | ||
45 | A { x: 0 } | ||
46 | } | ||
47 | } | ||
48 | fn test() { | ||
49 | let a = A::new(); | ||
50 | a.x; | ||
51 | } | ||
52 | "#, | ||
53 | expect![[r#" | ||
54 | 48..74 '{ ... }': A | ||
55 | 58..68 'A { x: 0 }': A | ||
56 | 65..66 '0': u32 | ||
57 | 87..121 '{ ...a.x; }': () | ||
58 | 97..98 'a': A | ||
59 | 101..107 'A::new': fn new() -> A | ||
60 | 101..109 'A::new()': A | ||
61 | 115..116 'a': A | ||
62 | 115..118 'a.x': u32 | ||
63 | "#]], | ||
64 | ); | ||
65 | } | ||
66 | |||
67 | #[test] | ||
68 | fn infer_associated_method_enum() { | ||
69 | check_infer( | ||
70 | r#" | ||
71 | enum A { B, C } | ||
72 | |||
73 | impl A { | ||
74 | pub fn b() -> A { | ||
75 | A::B | ||
76 | } | ||
77 | pub fn c() -> A { | ||
78 | A::C | ||
79 | } | ||
80 | } | ||
81 | fn test() { | ||
82 | let a = A::b(); | ||
83 | a; | ||
84 | let c = A::c(); | ||
85 | c; | ||
86 | } | ||
87 | "#, | ||
88 | expect![[r#" | ||
89 | 46..66 '{ ... }': A | ||
90 | 56..60 'A::B': A | ||
91 | 87..107 '{ ... }': A | ||
92 | 97..101 'A::C': A | ||
93 | 120..177 '{ ... c; }': () | ||
94 | 130..131 'a': A | ||
95 | 134..138 'A::b': fn b() -> A | ||
96 | 134..140 'A::b()': A | ||
97 | 146..147 'a': A | ||
98 | 157..158 'c': A | ||
99 | 161..165 'A::c': fn c() -> A | ||
100 | 161..167 'A::c()': A | ||
101 | 173..174 'c': A | ||
102 | "#]], | ||
103 | ); | ||
104 | } | ||
105 | |||
106 | #[test] | ||
107 | fn infer_associated_method_with_modules() { | ||
108 | check_infer( | ||
109 | r#" | ||
110 | mod a { | ||
111 | struct A; | ||
112 | impl A { pub fn thing() -> A { A {} }} | ||
113 | } | ||
114 | |||
115 | mod b { | ||
116 | struct B; | ||
117 | impl B { pub fn thing() -> u32 { 99 }} | ||
118 | |||
119 | mod c { | ||
120 | struct C; | ||
121 | impl C { pub fn thing() -> C { C {} }} | ||
122 | } | ||
123 | } | ||
124 | use b::c; | ||
125 | |||
126 | fn test() { | ||
127 | let x = a::A::thing(); | ||
128 | let y = b::B::thing(); | ||
129 | let z = c::C::thing(); | ||
130 | } | ||
131 | "#, | ||
132 | expect![[r#" | ||
133 | 55..63 '{ A {} }': A | ||
134 | 57..61 'A {}': A | ||
135 | 125..131 '{ 99 }': u32 | ||
136 | 127..129 '99': u32 | ||
137 | 201..209 '{ C {} }': C | ||
138 | 203..207 'C {}': C | ||
139 | 240..324 '{ ...g(); }': () | ||
140 | 250..251 'x': A | ||
141 | 254..265 'a::A::thing': fn thing() -> A | ||
142 | 254..267 'a::A::thing()': A | ||
143 | 277..278 'y': u32 | ||
144 | 281..292 'b::B::thing': fn thing() -> u32 | ||
145 | 281..294 'b::B::thing()': u32 | ||
146 | 304..305 'z': C | ||
147 | 308..319 'c::C::thing': fn thing() -> C | ||
148 | 308..321 'c::C::thing()': C | ||
149 | "#]], | ||
150 | ); | ||
151 | } | ||
152 | |||
153 | #[test] | ||
154 | fn infer_associated_method_generics() { | ||
155 | check_infer( | ||
156 | r#" | ||
157 | struct Gen<T> { | ||
158 | val: T | ||
159 | } | ||
160 | |||
161 | impl<T> Gen<T> { | ||
162 | pub fn make(val: T) -> Gen<T> { | ||
163 | Gen { val } | ||
164 | } | ||
165 | } | ||
166 | |||
167 | fn test() { | ||
168 | let a = Gen::make(0u32); | ||
169 | } | ||
170 | "#, | ||
171 | expect![[r#" | ||
172 | 63..66 'val': T | ||
173 | 81..108 '{ ... }': Gen<T> | ||
174 | 91..102 'Gen { val }': Gen<T> | ||
175 | 97..100 'val': T | ||
176 | 122..154 '{ ...32); }': () | ||
177 | 132..133 'a': Gen<u32> | ||
178 | 136..145 'Gen::make': fn make<u32>(u32) -> Gen<u32> | ||
179 | 136..151 'Gen::make(0u32)': Gen<u32> | ||
180 | 146..150 '0u32': u32 | ||
181 | "#]], | ||
182 | ); | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn infer_associated_method_generics_without_args() { | ||
187 | check_infer( | ||
188 | r#" | ||
189 | struct Gen<T> { | ||
190 | val: T | ||
191 | } | ||
192 | |||
193 | impl<T> Gen<T> { | ||
194 | pub fn make() -> Gen<T> { | ||
195 | loop { } | ||
196 | } | ||
197 | } | ||
198 | |||
199 | fn test() { | ||
200 | let a = Gen::<u32>::make(); | ||
201 | } | ||
202 | "#, | ||
203 | expect![[r#" | ||
204 | 75..99 '{ ... }': Gen<T> | ||
205 | 85..93 'loop { }': ! | ||
206 | 90..93 '{ }': () | ||
207 | 113..148 '{ ...e(); }': () | ||
208 | 123..124 'a': Gen<u32> | ||
209 | 127..143 'Gen::<...::make': fn make<u32>() -> Gen<u32> | ||
210 | 127..145 'Gen::<...make()': Gen<u32> | ||
211 | "#]], | ||
212 | ); | ||
213 | } | ||
214 | |||
215 | #[test] | ||
216 | fn infer_associated_method_generics_2_type_params_without_args() { | ||
217 | check_infer( | ||
218 | r#" | ||
219 | struct Gen<T, U> { | ||
220 | val: T, | ||
221 | val2: U, | ||
222 | } | ||
223 | |||
224 | impl<T> Gen<u32, T> { | ||
225 | pub fn make() -> Gen<u32,T> { | ||
226 | loop { } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | fn test() { | ||
231 | let a = Gen::<u32, u64>::make(); | ||
232 | } | ||
233 | "#, | ||
234 | expect![[r#" | ||
235 | 101..125 '{ ... }': Gen<u32, T> | ||
236 | 111..119 'loop { }': ! | ||
237 | 116..119 '{ }': () | ||
238 | 139..179 '{ ...e(); }': () | ||
239 | 149..150 'a': Gen<u32, u64> | ||
240 | 153..174 'Gen::<...::make': fn make<u64>() -> Gen<u32, u64> | ||
241 | 153..176 'Gen::<...make()': Gen<u32, u64> | ||
242 | "#]], | ||
243 | ); | ||
244 | } | ||
245 | |||
246 | #[test] | ||
247 | fn cross_crate_associated_method_call() { | ||
248 | check_types( | ||
249 | r#" | ||
250 | //- /main.rs crate:main deps:other_crate | ||
251 | fn test() { | ||
252 | let x = other_crate::foo::S::thing(); | ||
253 | x; | ||
254 | } //^ i128 | ||
255 | |||
256 | //- /lib.rs crate:other_crate | ||
257 | mod foo { | ||
258 | struct S; | ||
259 | impl S { | ||
260 | fn thing() -> i128 {} | ||
261 | } | ||
262 | } | ||
263 | "#, | ||
264 | ); | ||
265 | } | ||
266 | |||
267 | #[test] | ||
268 | fn infer_trait_method_simple() { | ||
269 | // the trait implementation is intentionally incomplete -- it shouldn't matter | ||
270 | check_infer( | ||
271 | r#" | ||
272 | trait Trait1 { | ||
273 | fn method(&self) -> u32; | ||
274 | } | ||
275 | struct S1; | ||
276 | impl Trait1 for S1 {} | ||
277 | trait Trait2 { | ||
278 | fn method(&self) -> i128; | ||
279 | } | ||
280 | struct S2; | ||
281 | impl Trait2 for S2 {} | ||
282 | fn test() { | ||
283 | S1.method(); // -> u32 | ||
284 | S2.method(); // -> i128 | ||
285 | } | ||
286 | "#, | ||
287 | expect![[r#" | ||
288 | 30..34 'self': &Self | ||
289 | 109..113 'self': &Self | ||
290 | 169..227 '{ ...i128 }': () | ||
291 | 175..177 'S1': S1 | ||
292 | 175..186 'S1.method()': u32 | ||
293 | 202..204 'S2': S2 | ||
294 | 202..213 'S2.method()': i128 | ||
295 | "#]], | ||
296 | ); | ||
297 | } | ||
298 | |||
299 | #[test] | ||
300 | fn infer_trait_method_scoped() { | ||
301 | // the trait implementation is intentionally incomplete -- it shouldn't matter | ||
302 | check_infer( | ||
303 | r#" | ||
304 | struct S; | ||
305 | mod foo { | ||
306 | pub trait Trait1 { | ||
307 | fn method(&self) -> u32; | ||
308 | } | ||
309 | impl Trait1 for super::S {} | ||
310 | } | ||
311 | mod bar { | ||
312 | pub trait Trait2 { | ||
313 | fn method(&self) -> i128; | ||
314 | } | ||
315 | impl Trait2 for super::S {} | ||
316 | } | ||
317 | |||
318 | mod foo_test { | ||
319 | use super::S; | ||
320 | use super::foo::Trait1; | ||
321 | fn test() { | ||
322 | S.method(); // -> u32 | ||
323 | } | ||
324 | } | ||
325 | |||
326 | mod bar_test { | ||
327 | use super::S; | ||
328 | use super::bar::Trait2; | ||
329 | fn test() { | ||
330 | S.method(); // -> i128 | ||
331 | } | ||
332 | } | ||
333 | "#, | ||
334 | expect![[r#" | ||
335 | 62..66 'self': &Self | ||
336 | 168..172 'self': &Self | ||
337 | 299..336 '{ ... }': () | ||
338 | 309..310 'S': S | ||
339 | 309..319 'S.method()': u32 | ||
340 | 415..453 '{ ... }': () | ||
341 | 425..426 'S': S | ||
342 | 425..435 'S.method()': i128 | ||
343 | "#]], | ||
344 | ); | ||
345 | } | ||
346 | |||
347 | #[test] | ||
348 | fn infer_trait_method_generic_1() { | ||
349 | // the trait implementation is intentionally incomplete -- it shouldn't matter | ||
350 | check_infer( | ||
351 | r#" | ||
352 | trait Trait<T> { | ||
353 | fn method(&self) -> T; | ||
354 | } | ||
355 | struct S; | ||
356 | impl Trait<u32> for S {} | ||
357 | fn test() { | ||
358 | S.method(); | ||
359 | } | ||
360 | "#, | ||
361 | expect![[r#" | ||
362 | 32..36 'self': &Self | ||
363 | 91..110 '{ ...d(); }': () | ||
364 | 97..98 'S': S | ||
365 | 97..107 'S.method()': u32 | ||
366 | "#]], | ||
367 | ); | ||
368 | } | ||
369 | |||
370 | #[test] | ||
371 | fn infer_trait_method_generic_more_params() { | ||
372 | // the trait implementation is intentionally incomplete -- it shouldn't matter | ||
373 | check_infer( | ||
374 | r#" | ||
375 | trait Trait<T1, T2, T3> { | ||
376 | fn method1(&self) -> (T1, T2, T3); | ||
377 | fn method2(&self) -> (T3, T2, T1); | ||
378 | } | ||
379 | struct S1; | ||
380 | impl Trait<u8, u16, u32> for S1 {} | ||
381 | struct S2; | ||
382 | impl<T> Trait<i8, i16, T> for S2 {} | ||
383 | fn test() { | ||
384 | S1.method1(); // u8, u16, u32 | ||
385 | S1.method2(); // u32, u16, u8 | ||
386 | S2.method1(); // i8, i16, {unknown} | ||
387 | S2.method2(); // {unknown}, i16, i8 | ||
388 | } | ||
389 | "#, | ||
390 | expect![[r#" | ||
391 | 42..46 'self': &Self | ||
392 | 81..85 'self': &Self | ||
393 | 209..360 '{ ..., i8 }': () | ||
394 | 215..217 'S1': S1 | ||
395 | 215..227 'S1.method1()': (u8, u16, u32) | ||
396 | 249..251 'S1': S1 | ||
397 | 249..261 'S1.method2()': (u32, u16, u8) | ||
398 | 283..285 'S2': S2 | ||
399 | 283..295 'S2.method1()': (i8, i16, {unknown}) | ||
400 | 323..325 'S2': S2 | ||
401 | 323..335 'S2.method2()': ({unknown}, i16, i8) | ||
402 | "#]], | ||
403 | ); | ||
404 | } | ||
405 | |||
406 | #[test] | ||
407 | fn infer_trait_method_generic_2() { | ||
408 | // the trait implementation is intentionally incomplete -- it shouldn't matter | ||
409 | check_infer( | ||
410 | r#" | ||
411 | trait Trait<T> { | ||
412 | fn method(&self) -> T; | ||
413 | } | ||
414 | struct S<T>(T); | ||
415 | impl<U> Trait<U> for S<U> {} | ||
416 | fn test() { | ||
417 | S(1u32).method(); | ||
418 | } | ||
419 | "#, | ||
420 | expect![[r#" | ||
421 | 32..36 'self': &Self | ||
422 | 101..126 '{ ...d(); }': () | ||
423 | 107..108 'S': S<u32>(u32) -> S<u32> | ||
424 | 107..114 'S(1u32)': S<u32> | ||
425 | 107..123 'S(1u32...thod()': u32 | ||
426 | 109..113 '1u32': u32 | ||
427 | "#]], | ||
428 | ); | ||
429 | } | ||
430 | |||
431 | #[test] | ||
432 | fn infer_trait_assoc_method() { | ||
433 | check_infer( | ||
434 | r#" | ||
435 | trait Default { | ||
436 | fn default() -> Self; | ||
437 | } | ||
438 | struct S; | ||
439 | impl Default for S {} | ||
440 | fn test() { | ||
441 | let s1: S = Default::default(); | ||
442 | let s2 = S::default(); | ||
443 | let s3 = <S as Default>::default(); | ||
444 | } | ||
445 | "#, | ||
446 | expect![[r#" | ||
447 | 86..192 '{ ...t(); }': () | ||
448 | 96..98 's1': S | ||
449 | 104..120 'Defaul...efault': fn default<S>() -> S | ||
450 | 104..122 'Defaul...ault()': S | ||
451 | 132..134 's2': S | ||
452 | 137..147 'S::default': fn default<S>() -> S | ||
453 | 137..149 'S::default()': S | ||
454 | 159..161 's3': S | ||
455 | 164..187 '<S as ...efault': fn default<S>() -> S | ||
456 | 164..189 '<S as ...ault()': S | ||
457 | "#]], | ||
458 | ); | ||
459 | } | ||
460 | |||
461 | #[test] | ||
462 | fn infer_trait_assoc_method_generics_1() { | ||
463 | check_infer( | ||
464 | r#" | ||
465 | trait Trait<T> { | ||
466 | fn make() -> T; | ||
467 | } | ||
468 | struct S; | ||
469 | impl Trait<u32> for S {} | ||
470 | struct G<T>; | ||
471 | impl<T> Trait<T> for G<T> {} | ||
472 | fn test() { | ||
473 | let a = S::make(); | ||
474 | let b = G::<u64>::make(); | ||
475 | let c: f64 = G::make(); | ||
476 | } | ||
477 | "#, | ||
478 | expect![[r#" | ||
479 | 126..210 '{ ...e(); }': () | ||
480 | 136..137 'a': u32 | ||
481 | 140..147 'S::make': fn make<S, u32>() -> u32 | ||
482 | 140..149 'S::make()': u32 | ||
483 | 159..160 'b': u64 | ||
484 | 163..177 'G::<u64>::make': fn make<G<u64>, u64>() -> u64 | ||
485 | 163..179 'G::<u6...make()': u64 | ||
486 | 189..190 'c': f64 | ||
487 | 198..205 'G::make': fn make<G<f64>, f64>() -> f64 | ||
488 | 198..207 'G::make()': f64 | ||
489 | "#]], | ||
490 | ); | ||
491 | } | ||
492 | |||
493 | #[test] | ||
494 | fn infer_trait_assoc_method_generics_2() { | ||
495 | check_infer( | ||
496 | r#" | ||
497 | trait Trait<T> { | ||
498 | fn make<U>() -> (T, U); | ||
499 | } | ||
500 | struct S; | ||
501 | impl Trait<u32> for S {} | ||
502 | struct G<T>; | ||
503 | impl<T> Trait<T> for G<T> {} | ||
504 | fn test() { | ||
505 | let a = S::make::<i64>(); | ||
506 | let b: (_, i64) = S::make(); | ||
507 | let c = G::<u32>::make::<i64>(); | ||
508 | let d: (u32, _) = G::make::<i64>(); | ||
509 | let e: (u32, i64) = G::make(); | ||
510 | } | ||
511 | "#, | ||
512 | expect![[r#" | ||
513 | 134..312 '{ ...e(); }': () | ||
514 | 144..145 'a': (u32, i64) | ||
515 | 148..162 'S::make::<i64>': fn make<S, u32, i64>() -> (u32, i64) | ||
516 | 148..164 'S::mak...i64>()': (u32, i64) | ||
517 | 174..175 'b': (u32, i64) | ||
518 | 188..195 'S::make': fn make<S, u32, i64>() -> (u32, i64) | ||
519 | 188..197 'S::make()': (u32, i64) | ||
520 | 207..208 'c': (u32, i64) | ||
521 | 211..232 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64) | ||
522 | 211..234 'G::<u3...i64>()': (u32, i64) | ||
523 | 244..245 'd': (u32, i64) | ||
524 | 258..272 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64) | ||
525 | 258..274 'G::mak...i64>()': (u32, i64) | ||
526 | 284..285 'e': (u32, i64) | ||
527 | 300..307 'G::make': fn make<G<u32>, u32, i64>() -> (u32, i64) | ||
528 | 300..309 'G::make()': (u32, i64) | ||
529 | "#]], | ||
530 | ); | ||
531 | } | ||
532 | |||
533 | #[test] | ||
534 | fn infer_trait_assoc_method_generics_3() { | ||
535 | check_infer( | ||
536 | r#" | ||
537 | trait Trait<T> { | ||
538 | fn make() -> (Self, T); | ||
539 | } | ||
540 | struct S<T>; | ||
541 | impl Trait<i64> for S<i32> {} | ||
542 | fn test() { | ||
543 | let a = S::make(); | ||
544 | } | ||
545 | "#, | ||
546 | expect![[r#" | ||
547 | 100..126 '{ ...e(); }': () | ||
548 | 110..111 'a': (S<i32>, i64) | ||
549 | 114..121 'S::make': fn make<S<i32>, i64>() -> (S<i32>, i64) | ||
550 | 114..123 'S::make()': (S<i32>, i64) | ||
551 | "#]], | ||
552 | ); | ||
553 | } | ||
554 | |||
555 | #[test] | ||
556 | fn infer_trait_assoc_method_generics_4() { | ||
557 | check_infer( | ||
558 | r#" | ||
559 | trait Trait<T> { | ||
560 | fn make() -> (Self, T); | ||
561 | } | ||
562 | struct S<T>; | ||
563 | impl Trait<i64> for S<u64> {} | ||
564 | impl Trait<i32> for S<u32> {} | ||
565 | fn test() { | ||
566 | let a: (S<u64>, _) = S::make(); | ||
567 | let b: (_, i32) = S::make(); | ||
568 | } | ||
569 | "#, | ||
570 | expect![[r#" | ||
571 | 130..202 '{ ...e(); }': () | ||
572 | 140..141 'a': (S<u64>, i64) | ||
573 | 157..164 'S::make': fn make<S<u64>, i64>() -> (S<u64>, i64) | ||
574 | 157..166 'S::make()': (S<u64>, i64) | ||
575 | 176..177 'b': (S<u32>, i32) | ||
576 | 190..197 'S::make': fn make<S<u32>, i32>() -> (S<u32>, i32) | ||
577 | 190..199 'S::make()': (S<u32>, i32) | ||
578 | "#]], | ||
579 | ); | ||
580 | } | ||
581 | |||
582 | #[test] | ||
583 | fn infer_trait_assoc_method_generics_5() { | ||
584 | check_infer( | ||
585 | r#" | ||
586 | trait Trait<T> { | ||
587 | fn make<U>() -> (Self, T, U); | ||
588 | } | ||
589 | struct S<T>; | ||
590 | impl Trait<i64> for S<u64> {} | ||
591 | fn test() { | ||
592 | let a = <S as Trait<i64>>::make::<u8>(); | ||
593 | let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>(); | ||
594 | } | ||
595 | "#, | ||
596 | expect![[r#" | ||
597 | 106..210 '{ ...>(); }': () | ||
598 | 116..117 'a': (S<u64>, i64, u8) | ||
599 | 120..149 '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8) | ||
600 | 120..151 '<S as ...<u8>()': (S<u64>, i64, u8) | ||
601 | 161..162 'b': (S<u64>, i64, u8) | ||
602 | 181..205 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8) | ||
603 | 181..207 'Trait:...<u8>()': (S<u64>, i64, u8) | ||
604 | "#]], | ||
605 | ); | ||
606 | } | ||
607 | |||
608 | #[test] | ||
609 | fn infer_call_trait_method_on_generic_param_1() { | ||
610 | check_infer( | ||
611 | r#" | ||
612 | trait Trait { | ||
613 | fn method(&self) -> u32; | ||
614 | } | ||
615 | fn test<T: Trait>(t: T) { | ||
616 | t.method(); | ||
617 | } | ||
618 | "#, | ||
619 | expect![[r#" | ||
620 | 29..33 'self': &Self | ||
621 | 63..64 't': T | ||
622 | 69..88 '{ ...d(); }': () | ||
623 | 75..76 't': T | ||
624 | 75..85 't.method()': u32 | ||
625 | "#]], | ||
626 | ); | ||
627 | } | ||
628 | |||
629 | #[test] | ||
630 | fn infer_call_trait_method_on_generic_param_2() { | ||
631 | check_infer( | ||
632 | r#" | ||
633 | trait Trait<T> { | ||
634 | fn method(&self) -> T; | ||
635 | } | ||
636 | fn test<U, T: Trait<U>>(t: T) { | ||
637 | t.method(); | ||
638 | } | ||
639 | "#, | ||
640 | expect![[r#" | ||
641 | 32..36 'self': &Self | ||
642 | 70..71 't': T | ||
643 | 76..95 '{ ...d(); }': () | ||
644 | 82..83 't': T | ||
645 | 82..92 't.method()': U | ||
646 | "#]], | ||
647 | ); | ||
648 | } | ||
649 | |||
650 | #[test] | ||
651 | fn infer_with_multiple_trait_impls() { | ||
652 | check_infer( | ||
653 | r#" | ||
654 | trait Into<T> { | ||
655 | fn into(self) -> T; | ||
656 | } | ||
657 | struct S; | ||
658 | impl Into<u32> for S {} | ||
659 | impl Into<u64> for S {} | ||
660 | fn test() { | ||
661 | let x: u32 = S.into(); | ||
662 | let y: u64 = S.into(); | ||
663 | let z = Into::<u64>::into(S); | ||
664 | } | ||
665 | "#, | ||
666 | expect![[r#" | ||
667 | 28..32 'self': Self | ||
668 | 110..201 '{ ...(S); }': () | ||
669 | 120..121 'x': u32 | ||
670 | 129..130 'S': S | ||
671 | 129..137 'S.into()': u32 | ||
672 | 147..148 'y': u64 | ||
673 | 156..157 'S': S | ||
674 | 156..164 'S.into()': u64 | ||
675 | 174..175 'z': u64 | ||
676 | 178..195 'Into::...::into': fn into<S, u64>(S) -> u64 | ||
677 | 178..198 'Into::...nto(S)': u64 | ||
678 | 196..197 'S': S | ||
679 | "#]], | ||
680 | ); | ||
681 | } | ||
682 | |||
683 | #[test] | ||
684 | fn method_resolution_unify_impl_self_type() { | ||
685 | check_types( | ||
686 | r#" | ||
687 | struct S<T>; | ||
688 | impl S<u32> { fn foo(&self) -> u8 {} } | ||
689 | impl S<i32> { fn foo(&self) -> i8 {} } | ||
690 | fn test() { (S::<u32>.foo(), S::<i32>.foo()); } | ||
691 | //^ (u8, i8) | ||
692 | "#, | ||
693 | ); | ||
694 | } | ||
695 | |||
696 | #[test] | ||
697 | fn method_resolution_trait_before_autoref() { | ||
698 | check_types( | ||
699 | r#" | ||
700 | trait Trait { fn foo(self) -> u128; } | ||
701 | struct S; | ||
702 | impl S { fn foo(&self) -> i8 { 0 } } | ||
703 | impl Trait for S { fn foo(self) -> u128 { 0 } } | ||
704 | fn test() { S.foo(); } | ||
705 | //^ u128 | ||
706 | "#, | ||
707 | ); | ||
708 | } | ||
709 | |||
710 | #[test] | ||
711 | fn method_resolution_by_value_before_autoref() { | ||
712 | check_types( | ||
713 | r#" | ||
714 | trait Clone { fn clone(&self) -> Self; } | ||
715 | struct S; | ||
716 | impl Clone for S {} | ||
717 | impl Clone for &S {} | ||
718 | fn test() { (S.clone(), (&S).clone(), (&&S).clone()); } | ||
719 | //^ (S, S, &S) | ||
720 | "#, | ||
721 | ); | ||
722 | } | ||
723 | |||
724 | #[test] | ||
725 | fn method_resolution_trait_before_autoderef() { | ||
726 | check_types( | ||
727 | r#" | ||
728 | trait Trait { fn foo(self) -> u128; } | ||
729 | struct S; | ||
730 | impl S { fn foo(self) -> i8 { 0 } } | ||
731 | impl Trait for &S { fn foo(self) -> u128 { 0 } } | ||
732 | fn test() { (&S).foo(); } | ||
733 | //^ u128 | ||
734 | "#, | ||
735 | ); | ||
736 | } | ||
737 | |||
738 | #[test] | ||
739 | fn method_resolution_impl_before_trait() { | ||
740 | check_types( | ||
741 | r#" | ||
742 | trait Trait { fn foo(self) -> u128; } | ||
743 | struct S; | ||
744 | impl S { fn foo(self) -> i8 { 0 } } | ||
745 | impl Trait for S { fn foo(self) -> u128 { 0 } } | ||
746 | fn test() { S.foo(); } | ||
747 | //^ i8 | ||
748 | "#, | ||
749 | ); | ||
750 | } | ||
751 | |||
752 | #[test] | ||
753 | fn method_resolution_impl_ref_before_trait() { | ||
754 | check_types( | ||
755 | r#" | ||
756 | trait Trait { fn foo(self) -> u128; } | ||
757 | struct S; | ||
758 | impl S { fn foo(&self) -> i8 { 0 } } | ||
759 | impl Trait for &S { fn foo(self) -> u128 { 0 } } | ||
760 | fn test() { S.foo(); } | ||
761 | //^ i8 | ||
762 | "#, | ||
763 | ); | ||
764 | } | ||
765 | |||
766 | #[test] | ||
767 | fn method_resolution_trait_autoderef() { | ||
768 | check_types( | ||
769 | r#" | ||
770 | trait Trait { fn foo(self) -> u128; } | ||
771 | struct S; | ||
772 | impl Trait for S { fn foo(self) -> u128 { 0 } } | ||
773 | fn test() { (&S).foo(); } | ||
774 | //^ u128 | ||
775 | "#, | ||
776 | ); | ||
777 | } | ||
778 | |||
779 | #[test] | ||
780 | fn method_resolution_unsize_array() { | ||
781 | check_types( | ||
782 | r#" | ||
783 | #[lang = "slice"] | ||
784 | impl<T> [T] { | ||
785 | fn len(&self) -> usize { loop {} } | ||
786 | } | ||
787 | fn test() { | ||
788 | let a = [1, 2, 3]; | ||
789 | a.len(); | ||
790 | } //^ usize | ||
791 | "#, | ||
792 | ); | ||
793 | } | ||
794 | |||
795 | #[test] | ||
796 | fn method_resolution_trait_from_prelude() { | ||
797 | check_types( | ||
798 | r#" | ||
799 | //- /main.rs crate:main deps:other_crate | ||
800 | struct S; | ||
801 | impl Clone for S {} | ||
802 | |||
803 | fn test() { | ||
804 | S.clone(); | ||
805 | //^ S | ||
806 | } | ||
807 | |||
808 | //- /lib.rs crate:other_crate | ||
809 | #[prelude_import] use foo::*; | ||
810 | |||
811 | mod foo { | ||
812 | trait Clone { | ||
813 | fn clone(&self) -> Self; | ||
814 | } | ||
815 | } | ||
816 | "#, | ||
817 | ); | ||
818 | } | ||
819 | |||
820 | #[test] | ||
821 | fn method_resolution_where_clause_for_unknown_trait() { | ||
822 | // The blanket impl currently applies because we ignore the unresolved where clause | ||
823 | check_types( | ||
824 | r#" | ||
825 | trait Trait { fn foo(self) -> u128; } | ||
826 | struct S; | ||
827 | impl<T> Trait for T where T: UnknownTrait {} | ||
828 | fn test() { (&S).foo(); } | ||
829 | //^ u128 | ||
830 | "#, | ||
831 | ); | ||
832 | } | ||
833 | |||
834 | #[test] | ||
835 | fn method_resolution_where_clause_not_met() { | ||
836 | // The blanket impl shouldn't apply because we can't prove S: Clone | ||
837 | // This is also to make sure that we don't resolve to the foo method just | ||
838 | // because that's the only method named foo we can find, which would make | ||
839 | // the below tests not work | ||
840 | check_types( | ||
841 | r#" | ||
842 | trait Clone {} | ||
843 | trait Trait { fn foo(self) -> u128; } | ||
844 | struct S; | ||
845 | impl<T> Trait for T where T: Clone {} | ||
846 | fn test() { (&S).foo(); } | ||
847 | //^ {unknown} | ||
848 | "#, | ||
849 | ); | ||
850 | } | ||
851 | |||
852 | #[test] | ||
853 | fn method_resolution_where_clause_inline_not_met() { | ||
854 | // The blanket impl shouldn't apply because we can't prove S: Clone | ||
855 | check_types( | ||
856 | r#" | ||
857 | trait Clone {} | ||
858 | trait Trait { fn foo(self) -> u128; } | ||
859 | struct S; | ||
860 | impl<T: Clone> Trait for T {} | ||
861 | fn test() { (&S).foo(); } | ||
862 | //^ {unknown} | ||
863 | "#, | ||
864 | ); | ||
865 | } | ||
866 | |||
867 | #[test] | ||
868 | fn method_resolution_where_clause_1() { | ||
869 | check_types( | ||
870 | r#" | ||
871 | trait Clone {} | ||
872 | trait Trait { fn foo(self) -> u128; } | ||
873 | struct S; | ||
874 | impl Clone for S {} | ||
875 | impl<T> Trait for T where T: Clone {} | ||
876 | fn test() { S.foo(); } | ||
877 | //^ u128 | ||
878 | "#, | ||
879 | ); | ||
880 | } | ||
881 | |||
882 | #[test] | ||
883 | fn method_resolution_where_clause_2() { | ||
884 | check_types( | ||
885 | r#" | ||
886 | trait Into<T> { fn into(self) -> T; } | ||
887 | trait From<T> { fn from(other: T) -> Self; } | ||
888 | struct S1; | ||
889 | struct S2; | ||
890 | impl From<S2> for S1 {} | ||
891 | impl<T, U> Into<U> for T where U: From<T> {} | ||
892 | fn test() { S2.into(); } | ||
893 | //^ {unknown} | ||
894 | "#, | ||
895 | ); | ||
896 | } | ||
897 | |||
898 | #[test] | ||
899 | fn method_resolution_where_clause_inline() { | ||
900 | check_types( | ||
901 | r#" | ||
902 | trait Into<T> { fn into(self) -> T; } | ||
903 | trait From<T> { fn from(other: T) -> Self; } | ||
904 | struct S1; | ||
905 | struct S2; | ||
906 | impl From<S2> for S1 {} | ||
907 | impl<T, U: From<T>> Into<U> for T {} | ||
908 | fn test() { S2.into(); } | ||
909 | //^ {unknown} | ||
910 | "#, | ||
911 | ); | ||
912 | } | ||
913 | |||
914 | #[test] | ||
915 | fn method_resolution_overloaded_method() { | ||
916 | test_utils::mark::check!(impl_self_type_match_without_receiver); | ||
917 | check_types( | ||
918 | r#" | ||
919 | struct Wrapper<T>(T); | ||
920 | struct Foo<T>(T); | ||
921 | struct Bar<T>(T); | ||
922 | |||
923 | impl<T> Wrapper<Foo<T>> { | ||
924 | pub fn new(foo_: T) -> Self { | ||
925 | Wrapper(Foo(foo_)) | ||
926 | } | ||
927 | } | ||
928 | |||
929 | impl<T> Wrapper<Bar<T>> { | ||
930 | pub fn new(bar_: T) -> Self { | ||
931 | Wrapper(Bar(bar_)) | ||
932 | } | ||
933 | } | ||
934 | |||
935 | fn main() { | ||
936 | let a = Wrapper::<Foo<f32>>::new(1.0); | ||
937 | let b = Wrapper::<Bar<f32>>::new(1.0); | ||
938 | (a, b); | ||
939 | //^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>) | ||
940 | } | ||
941 | "#, | ||
942 | ); | ||
943 | } | ||
944 | |||
945 | #[test] | ||
946 | fn method_resolution_encountering_fn_type() { | ||
947 | check_types( | ||
948 | r#" | ||
949 | //- /main.rs | ||
950 | fn foo() {} | ||
951 | trait FnOnce { fn call(self); } | ||
952 | fn test() { foo.call(); } | ||
953 | //^ {unknown} | ||
954 | "#, | ||
955 | ); | ||
956 | } | ||
957 | |||
958 | #[test] | ||
959 | fn method_resolution_non_parameter_type() { | ||
960 | check_types( | ||
961 | r#" | ||
962 | mod a { | ||
963 | pub trait Foo { | ||
964 | fn foo(&self); | ||
965 | } | ||
966 | } | ||
967 | |||
968 | struct Wrapper<T>(T); | ||
969 | fn foo<T>(t: Wrapper<T>) | ||
970 | where | ||
971 | Wrapper<T>: a::Foo, | ||
972 | { | ||
973 | t.foo(); | ||
974 | } //^ {unknown} | ||
975 | "#, | ||
976 | ); | ||
977 | } | ||
978 | |||
979 | #[test] | ||
980 | fn method_resolution_3373() { | ||
981 | check_types( | ||
982 | r#" | ||
983 | struct A<T>(T); | ||
984 | |||
985 | impl A<i32> { | ||
986 | fn from(v: i32) -> A<i32> { A(v) } | ||
987 | } | ||
988 | |||
989 | fn main() { | ||
990 | A::from(3); | ||
991 | } //^ A<i32> | ||
992 | "#, | ||
993 | ); | ||
994 | } | ||
995 | |||
996 | #[test] | ||
997 | fn method_resolution_slow() { | ||
998 | // this can get quite slow if we set the solver size limit too high | ||
999 | check_types( | ||
1000 | r#" | ||
1001 | trait SendX {} | ||
1002 | |||
1003 | struct S1; impl SendX for S1 {} | ||
1004 | struct S2; impl SendX for S2 {} | ||
1005 | struct U1; | ||
1006 | |||
1007 | trait Trait { fn method(self); } | ||
1008 | |||
1009 | struct X1<A, B> {} | ||
1010 | impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {} | ||
1011 | |||
1012 | struct S<B, C> {} | ||
1013 | |||
1014 | trait FnX {} | ||
1015 | |||
1016 | impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} | ||
1017 | |||
1018 | fn test() { (S {}).method(); } | ||
1019 | //^ () | ||
1020 | "#, | ||
1021 | ); | ||
1022 | } | ||
1023 | |||
1024 | #[test] | ||
1025 | fn dyn_trait_super_trait_not_in_scope() { | ||
1026 | check_infer( | ||
1027 | r#" | ||
1028 | mod m { | ||
1029 | pub trait SuperTrait { | ||
1030 | fn foo(&self) -> u32 { 0 } | ||
1031 | } | ||
1032 | } | ||
1033 | trait Trait: m::SuperTrait {} | ||
1034 | |||
1035 | struct S; | ||
1036 | impl m::SuperTrait for S {} | ||
1037 | impl Trait for S {} | ||
1038 | |||
1039 | fn test(d: &dyn Trait) { | ||
1040 | d.foo(); | ||
1041 | } | ||
1042 | "#, | ||
1043 | expect![[r#" | ||
1044 | 51..55 'self': &Self | ||
1045 | 64..69 '{ 0 }': u32 | ||
1046 | 66..67 '0': u32 | ||
1047 | 176..177 'd': &dyn Trait | ||
1048 | 191..207 '{ ...o(); }': () | ||
1049 | 197..198 'd': &dyn Trait | ||
1050 | 197..204 'd.foo()': u32 | ||
1051 | "#]], | ||
1052 | ); | ||
1053 | } | ||
diff --git a/crates/hir_ty/src/tests/never_type.rs b/crates/hir_ty/src/tests/never_type.rs new file mode 100644 index 000000000..49538b572 --- /dev/null +++ b/crates/hir_ty/src/tests/never_type.rs | |||
@@ -0,0 +1,409 @@ | |||
1 | use expect::expect; | ||
2 | |||
3 | use super::{check_infer_with_mismatches, check_types}; | ||
4 | |||
5 | #[test] | ||
6 | fn infer_never1() { | ||
7 | check_types( | ||
8 | r#" | ||
9 | fn test() { | ||
10 | let t = return; | ||
11 | t; | ||
12 | } //^ ! | ||
13 | "#, | ||
14 | ); | ||
15 | } | ||
16 | |||
17 | #[test] | ||
18 | fn infer_never2() { | ||
19 | check_types( | ||
20 | r#" | ||
21 | fn gen<T>() -> T { loop {} } | ||
22 | |||
23 | fn test() { | ||
24 | let a = gen(); | ||
25 | if false { a } else { loop {} }; | ||
26 | a; | ||
27 | } //^ ! | ||
28 | "#, | ||
29 | ); | ||
30 | } | ||
31 | |||
32 | #[test] | ||
33 | fn infer_never3() { | ||
34 | check_types( | ||
35 | r#" | ||
36 | fn gen<T>() -> T { loop {} } | ||
37 | |||
38 | fn test() { | ||
39 | let a = gen(); | ||
40 | if false { loop {} } else { a }; | ||
41 | a; | ||
42 | //^ ! | ||
43 | } | ||
44 | "#, | ||
45 | ); | ||
46 | } | ||
47 | |||
48 | #[test] | ||
49 | fn never_type_in_generic_args() { | ||
50 | check_types( | ||
51 | r#" | ||
52 | enum Option<T> { None, Some(T) } | ||
53 | |||
54 | fn test() { | ||
55 | let a = if true { Option::None } else { Option::Some(return) }; | ||
56 | a; | ||
57 | } //^ Option<!> | ||
58 | "#, | ||
59 | ); | ||
60 | } | ||
61 | |||
62 | #[test] | ||
63 | fn never_type_can_be_reinferred1() { | ||
64 | check_types( | ||
65 | r#" | ||
66 | fn gen<T>() -> T { loop {} } | ||
67 | |||
68 | fn test() { | ||
69 | let a = gen(); | ||
70 | if false { loop {} } else { a }; | ||
71 | a; | ||
72 | //^ () | ||
73 | if false { a }; | ||
74 | } | ||
75 | "#, | ||
76 | ); | ||
77 | } | ||
78 | |||
79 | #[test] | ||
80 | fn never_type_can_be_reinferred2() { | ||
81 | check_types( | ||
82 | r#" | ||
83 | enum Option<T> { None, Some(T) } | ||
84 | |||
85 | fn test() { | ||
86 | let a = if true { Option::None } else { Option::Some(return) }; | ||
87 | a; | ||
88 | //^ Option<i32> | ||
89 | match 42 { | ||
90 | 42 => a, | ||
91 | _ => Option::Some(42), | ||
92 | }; | ||
93 | } | ||
94 | "#, | ||
95 | ); | ||
96 | } | ||
97 | |||
98 | #[test] | ||
99 | fn never_type_can_be_reinferred3() { | ||
100 | check_types( | ||
101 | r#" | ||
102 | enum Option<T> { None, Some(T) } | ||
103 | |||
104 | fn test() { | ||
105 | let a = if true { Option::None } else { Option::Some(return) }; | ||
106 | a; | ||
107 | //^ Option<&str> | ||
108 | match 42 { | ||
109 | 42 => a, | ||
110 | _ => Option::Some("str"), | ||
111 | }; | ||
112 | } | ||
113 | "#, | ||
114 | ); | ||
115 | } | ||
116 | |||
117 | #[test] | ||
118 | fn match_no_arm() { | ||
119 | check_types( | ||
120 | r#" | ||
121 | enum Void {} | ||
122 | |||
123 | fn test(a: Void) { | ||
124 | let t = match a {}; | ||
125 | t; | ||
126 | } //^ ! | ||
127 | "#, | ||
128 | ); | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn match_unknown_arm() { | ||
133 | check_types( | ||
134 | r#" | ||
135 | fn test(a: Option) { | ||
136 | let t = match 0 { | ||
137 | _ => unknown, | ||
138 | }; | ||
139 | t; | ||
140 | } //^ {unknown} | ||
141 | "#, | ||
142 | ); | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn if_never() { | ||
147 | check_types( | ||
148 | r#" | ||
149 | fn test() { | ||
150 | let i = if true { | ||
151 | loop {} | ||
152 | } else { | ||
153 | 3.0 | ||
154 | }; | ||
155 | i; | ||
156 | } //^ f64 | ||
157 | "#, | ||
158 | ); | ||
159 | } | ||
160 | |||
161 | #[test] | ||
162 | fn if_else_never() { | ||
163 | check_types( | ||
164 | r#" | ||
165 | fn test(input: bool) { | ||
166 | let i = if input { | ||
167 | 2.0 | ||
168 | } else { | ||
169 | return | ||
170 | }; | ||
171 | i; | ||
172 | } //^ f64 | ||
173 | "#, | ||
174 | ); | ||
175 | } | ||
176 | |||
177 | #[test] | ||
178 | fn match_first_arm_never() { | ||
179 | check_types( | ||
180 | r#" | ||
181 | fn test(a: i32) { | ||
182 | let i = match a { | ||
183 | 1 => return, | ||
184 | 2 => 2.0, | ||
185 | 3 => loop {}, | ||
186 | _ => 3.0, | ||
187 | }; | ||
188 | i; | ||
189 | } //^ f64 | ||
190 | "#, | ||
191 | ); | ||
192 | } | ||
193 | |||
194 | #[test] | ||
195 | fn match_second_arm_never() { | ||
196 | check_types( | ||
197 | r#" | ||
198 | fn test(a: i32) { | ||
199 | let i = match a { | ||
200 | 1 => 3.0, | ||
201 | 2 => loop {}, | ||
202 | 3 => 3.0, | ||
203 | _ => return, | ||
204 | }; | ||
205 | i; | ||
206 | } //^ f64 | ||
207 | "#, | ||
208 | ); | ||
209 | } | ||
210 | |||
211 | #[test] | ||
212 | fn match_all_arms_never() { | ||
213 | check_types( | ||
214 | r#" | ||
215 | fn test(a: i32) { | ||
216 | let i = match a { | ||
217 | 2 => return, | ||
218 | _ => loop {}, | ||
219 | }; | ||
220 | i; | ||
221 | } //^ ! | ||
222 | "#, | ||
223 | ); | ||
224 | } | ||
225 | |||
226 | #[test] | ||
227 | fn match_no_never_arms() { | ||
228 | check_types( | ||
229 | r#" | ||
230 | fn test(a: i32) { | ||
231 | let i = match a { | ||
232 | 2 => 2.0, | ||
233 | _ => 3.0, | ||
234 | }; | ||
235 | i; | ||
236 | } //^ f64 | ||
237 | "#, | ||
238 | ); | ||
239 | } | ||
240 | |||
241 | #[test] | ||
242 | fn diverging_expression_1() { | ||
243 | check_infer_with_mismatches( | ||
244 | r" | ||
245 | //- /main.rs | ||
246 | fn test1() { | ||
247 | let x: u32 = return; | ||
248 | } | ||
249 | fn test2() { | ||
250 | let x: u32 = { return; }; | ||
251 | } | ||
252 | fn test3() { | ||
253 | let x: u32 = loop {}; | ||
254 | } | ||
255 | fn test4() { | ||
256 | let x: u32 = { loop {} }; | ||
257 | } | ||
258 | fn test5() { | ||
259 | let x: u32 = { if true { loop {}; } else { loop {}; } }; | ||
260 | } | ||
261 | fn test6() { | ||
262 | let x: u32 = { let y: u32 = { loop {}; }; }; | ||
263 | } | ||
264 | ", | ||
265 | expect![[r" | ||
266 | 11..39 '{ ...urn; }': () | ||
267 | 21..22 'x': u32 | ||
268 | 30..36 'return': ! | ||
269 | 51..84 '{ ...; }; }': () | ||
270 | 61..62 'x': u32 | ||
271 | 70..81 '{ return; }': u32 | ||
272 | 72..78 'return': ! | ||
273 | 96..125 '{ ... {}; }': () | ||
274 | 106..107 'x': u32 | ||
275 | 115..122 'loop {}': ! | ||
276 | 120..122 '{}': () | ||
277 | 137..170 '{ ...} }; }': () | ||
278 | 147..148 'x': u32 | ||
279 | 156..167 '{ loop {} }': u32 | ||
280 | 158..165 'loop {}': ! | ||
281 | 163..165 '{}': () | ||
282 | 182..246 '{ ...} }; }': () | ||
283 | 192..193 'x': u32 | ||
284 | 201..243 '{ if t...}; } }': u32 | ||
285 | 203..241 'if tru... {}; }': u32 | ||
286 | 206..210 'true': bool | ||
287 | 211..223 '{ loop {}; }': u32 | ||
288 | 213..220 'loop {}': ! | ||
289 | 218..220 '{}': () | ||
290 | 229..241 '{ loop {}; }': u32 | ||
291 | 231..238 'loop {}': ! | ||
292 | 236..238 '{}': () | ||
293 | 258..310 '{ ...; }; }': () | ||
294 | 268..269 'x': u32 | ||
295 | 277..307 '{ let ...; }; }': u32 | ||
296 | 283..284 'y': u32 | ||
297 | 292..304 '{ loop {}; }': u32 | ||
298 | 294..301 'loop {}': ! | ||
299 | 299..301 '{}': () | ||
300 | "]], | ||
301 | ); | ||
302 | } | ||
303 | |||
304 | #[test] | ||
305 | fn diverging_expression_2() { | ||
306 | check_infer_with_mismatches( | ||
307 | r#" | ||
308 | //- /main.rs | ||
309 | fn test1() { | ||
310 | // should give type mismatch | ||
311 | let x: u32 = { loop {}; "foo" }; | ||
312 | } | ||
313 | "#, | ||
314 | expect![[r#" | ||
315 | 11..84 '{ ..." }; }': () | ||
316 | 54..55 'x': u32 | ||
317 | 63..81 '{ loop...foo" }': &str | ||
318 | 65..72 'loop {}': ! | ||
319 | 70..72 '{}': () | ||
320 | 74..79 '"foo"': &str | ||
321 | 63..81: expected u32, got &str | ||
322 | 74..79: expected u32, got &str | ||
323 | "#]], | ||
324 | ); | ||
325 | } | ||
326 | |||
327 | #[test] | ||
328 | fn diverging_expression_3_break() { | ||
329 | check_infer_with_mismatches( | ||
330 | r" | ||
331 | //- /main.rs | ||
332 | fn test1() { | ||
333 | // should give type mismatch | ||
334 | let x: u32 = { loop { break; } }; | ||
335 | } | ||
336 | fn test2() { | ||
337 | // should give type mismatch | ||
338 | let x: u32 = { for a in b { break; }; }; | ||
339 | // should give type mismatch as well | ||
340 | let x: u32 = { for a in b {}; }; | ||
341 | // should give type mismatch as well | ||
342 | let x: u32 = { for a in b { return; }; }; | ||
343 | } | ||
344 | fn test3() { | ||
345 | // should give type mismatch | ||
346 | let x: u32 = { while true { break; }; }; | ||
347 | // should give type mismatch as well -- there's an implicit break, even if it's never hit | ||
348 | let x: u32 = { while true {}; }; | ||
349 | // should give type mismatch as well | ||
350 | let x: u32 = { while true { return; }; }; | ||
351 | } | ||
352 | ", | ||
353 | expect![[r" | ||
354 | 11..85 '{ ...} }; }': () | ||
355 | 54..55 'x': u32 | ||
356 | 63..82 '{ loop...k; } }': () | ||
357 | 65..80 'loop { break; }': () | ||
358 | 70..80 '{ break; }': () | ||
359 | 72..77 'break': ! | ||
360 | 63..82: expected u32, got () | ||
361 | 65..80: expected u32, got () | ||
362 | 97..343 '{ ...; }; }': () | ||
363 | 140..141 'x': u32 | ||
364 | 149..175 '{ for ...; }; }': () | ||
365 | 151..172 'for a ...eak; }': () | ||
366 | 155..156 'a': {unknown} | ||
367 | 160..161 'b': {unknown} | ||
368 | 162..172 '{ break; }': () | ||
369 | 164..169 'break': ! | ||
370 | 226..227 'x': u32 | ||
371 | 235..253 '{ for ... {}; }': () | ||
372 | 237..250 'for a in b {}': () | ||
373 | 241..242 'a': {unknown} | ||
374 | 246..247 'b': {unknown} | ||
375 | 248..250 '{}': () | ||
376 | 304..305 'x': u32 | ||
377 | 313..340 '{ for ...; }; }': () | ||
378 | 315..337 'for a ...urn; }': () | ||
379 | 319..320 'a': {unknown} | ||
380 | 324..325 'b': {unknown} | ||
381 | 326..337 '{ return; }': () | ||
382 | 328..334 'return': ! | ||
383 | 149..175: expected u32, got () | ||
384 | 235..253: expected u32, got () | ||
385 | 313..340: expected u32, got () | ||
386 | 355..654 '{ ...; }; }': () | ||
387 | 398..399 'x': u32 | ||
388 | 407..433 '{ whil...; }; }': () | ||
389 | 409..430 'while ...eak; }': () | ||
390 | 415..419 'true': bool | ||
391 | 420..430 '{ break; }': () | ||
392 | 422..427 'break': ! | ||
393 | 537..538 'x': u32 | ||
394 | 546..564 '{ whil... {}; }': () | ||
395 | 548..561 'while true {}': () | ||
396 | 554..558 'true': bool | ||
397 | 559..561 '{}': () | ||
398 | 615..616 'x': u32 | ||
399 | 624..651 '{ whil...; }; }': () | ||
400 | 626..648 'while ...urn; }': () | ||
401 | 632..636 'true': bool | ||
402 | 637..648 '{ return; }': () | ||
403 | 639..645 'return': ! | ||
404 | 407..433: expected u32, got () | ||
405 | 546..564: expected u32, got () | ||
406 | 624..651: expected u32, got () | ||
407 | "]], | ||
408 | ); | ||
409 | } | ||
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs new file mode 100644 index 000000000..39fabf7eb --- /dev/null +++ b/crates/hir_ty/src/tests/patterns.rs | |||
@@ -0,0 +1,656 @@ | |||
1 | use expect::expect; | ||
2 | use test_utils::mark; | ||
3 | |||
4 | use super::{check_infer, check_infer_with_mismatches}; | ||
5 | |||
6 | #[test] | ||
7 | fn infer_pattern() { | ||
8 | check_infer( | ||
9 | r#" | ||
10 | fn test(x: &i32) { | ||
11 | let y = x; | ||
12 | let &z = x; | ||
13 | let a = z; | ||
14 | let (c, d) = (1, "hello"); | ||
15 | |||
16 | for (e, f) in some_iter { | ||
17 | let g = e; | ||
18 | } | ||
19 | |||
20 | if let [val] = opt { | ||
21 | let h = val; | ||
22 | } | ||
23 | |||
24 | let lambda = |a: u64, b, c: i32| { a + b; c }; | ||
25 | |||
26 | let ref ref_to_x = x; | ||
27 | let mut mut_x = x; | ||
28 | let ref mut mut_ref_to_x = x; | ||
29 | let k = mut_ref_to_x; | ||
30 | } | ||
31 | "#, | ||
32 | expect![[r#" | ||
33 | 8..9 'x': &i32 | ||
34 | 17..368 '{ ...o_x; }': () | ||
35 | 27..28 'y': &i32 | ||
36 | 31..32 'x': &i32 | ||
37 | 42..44 '&z': &i32 | ||
38 | 43..44 'z': i32 | ||
39 | 47..48 'x': &i32 | ||
40 | 58..59 'a': i32 | ||
41 | 62..63 'z': i32 | ||
42 | 73..79 '(c, d)': (i32, &str) | ||
43 | 74..75 'c': i32 | ||
44 | 77..78 'd': &str | ||
45 | 82..94 '(1, "hello")': (i32, &str) | ||
46 | 83..84 '1': i32 | ||
47 | 86..93 '"hello"': &str | ||
48 | 101..151 'for (e... }': () | ||
49 | 105..111 '(e, f)': ({unknown}, {unknown}) | ||
50 | 106..107 'e': {unknown} | ||
51 | 109..110 'f': {unknown} | ||
52 | 115..124 'some_iter': {unknown} | ||
53 | 125..151 '{ ... }': () | ||
54 | 139..140 'g': {unknown} | ||
55 | 143..144 'e': {unknown} | ||
56 | 157..204 'if let... }': () | ||
57 | 164..169 '[val]': [{unknown}] | ||
58 | 165..168 'val': {unknown} | ||
59 | 172..175 'opt': [{unknown}] | ||
60 | 176..204 '{ ... }': () | ||
61 | 190..191 'h': {unknown} | ||
62 | 194..197 'val': {unknown} | ||
63 | 214..220 'lambda': |u64, u64, i32| -> i32 | ||
64 | 223..255 '|a: u6...b; c }': |u64, u64, i32| -> i32 | ||
65 | 224..225 'a': u64 | ||
66 | 232..233 'b': u64 | ||
67 | 235..236 'c': i32 | ||
68 | 243..255 '{ a + b; c }': i32 | ||
69 | 245..246 'a': u64 | ||
70 | 245..250 'a + b': u64 | ||
71 | 249..250 'b': u64 | ||
72 | 252..253 'c': i32 | ||
73 | 266..278 'ref ref_to_x': &&i32 | ||
74 | 281..282 'x': &i32 | ||
75 | 292..301 'mut mut_x': &i32 | ||
76 | 304..305 'x': &i32 | ||
77 | 315..335 'ref mu...f_to_x': &mut &i32 | ||
78 | 338..339 'x': &i32 | ||
79 | 349..350 'k': &mut &i32 | ||
80 | 353..365 'mut_ref_to_x': &mut &i32 | ||
81 | "#]], | ||
82 | ); | ||
83 | } | ||
84 | |||
85 | #[test] | ||
86 | fn infer_literal_pattern() { | ||
87 | check_infer_with_mismatches( | ||
88 | r#" | ||
89 | fn any<T>() -> T { loop {} } | ||
90 | fn test(x: &i32) { | ||
91 | if let "foo" = any() {} | ||
92 | if let 1 = any() {} | ||
93 | if let 1u32 = any() {} | ||
94 | if let 1f32 = any() {} | ||
95 | if let 1.0 = any() {} | ||
96 | if let true = any() {} | ||
97 | } | ||
98 | "#, | ||
99 | expect![[r#" | ||
100 | 17..28 '{ loop {} }': T | ||
101 | 19..26 'loop {}': ! | ||
102 | 24..26 '{}': () | ||
103 | 37..38 'x': &i32 | ||
104 | 46..208 '{ ...) {} }': () | ||
105 | 52..75 'if let...y() {}': () | ||
106 | 59..64 '"foo"': &str | ||
107 | 59..64 '"foo"': &str | ||
108 | 67..70 'any': fn any<&str>() -> &str | ||
109 | 67..72 'any()': &str | ||
110 | 73..75 '{}': () | ||
111 | 80..99 'if let...y() {}': () | ||
112 | 87..88 '1': i32 | ||
113 | 87..88 '1': i32 | ||
114 | 91..94 'any': fn any<i32>() -> i32 | ||
115 | 91..96 'any()': i32 | ||
116 | 97..99 '{}': () | ||
117 | 104..126 'if let...y() {}': () | ||
118 | 111..115 '1u32': u32 | ||
119 | 111..115 '1u32': u32 | ||
120 | 118..121 'any': fn any<u32>() -> u32 | ||
121 | 118..123 'any()': u32 | ||
122 | 124..126 '{}': () | ||
123 | 131..153 'if let...y() {}': () | ||
124 | 138..142 '1f32': f32 | ||
125 | 138..142 '1f32': f32 | ||
126 | 145..148 'any': fn any<f32>() -> f32 | ||
127 | 145..150 'any()': f32 | ||
128 | 151..153 '{}': () | ||
129 | 158..179 'if let...y() {}': () | ||
130 | 165..168 '1.0': f64 | ||
131 | 165..168 '1.0': f64 | ||
132 | 171..174 'any': fn any<f64>() -> f64 | ||
133 | 171..176 'any()': f64 | ||
134 | 177..179 '{}': () | ||
135 | 184..206 'if let...y() {}': () | ||
136 | 191..195 'true': bool | ||
137 | 191..195 'true': bool | ||
138 | 198..201 'any': fn any<bool>() -> bool | ||
139 | 198..203 'any()': bool | ||
140 | 204..206 '{}': () | ||
141 | "#]], | ||
142 | ); | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn infer_range_pattern() { | ||
147 | check_infer_with_mismatches( | ||
148 | r#" | ||
149 | fn test(x: &i32) { | ||
150 | if let 1..76 = 2u32 {} | ||
151 | if let 1..=76 = 2u32 {} | ||
152 | } | ||
153 | "#, | ||
154 | expect![[r#" | ||
155 | 8..9 'x': &i32 | ||
156 | 17..75 '{ ...2 {} }': () | ||
157 | 23..45 'if let...u32 {}': () | ||
158 | 30..35 '1..76': u32 | ||
159 | 38..42 '2u32': u32 | ||
160 | 43..45 '{}': () | ||
161 | 50..73 'if let...u32 {}': () | ||
162 | 57..63 '1..=76': u32 | ||
163 | 66..70 '2u32': u32 | ||
164 | 71..73 '{}': () | ||
165 | "#]], | ||
166 | ); | ||
167 | } | ||
168 | |||
169 | #[test] | ||
170 | fn infer_pattern_match_ergonomics() { | ||
171 | check_infer( | ||
172 | r#" | ||
173 | struct A<T>(T); | ||
174 | |||
175 | fn test() { | ||
176 | let A(n) = &A(1); | ||
177 | let A(n) = &mut A(1); | ||
178 | } | ||
179 | "#, | ||
180 | expect![[r#" | ||
181 | 27..78 '{ ...(1); }': () | ||
182 | 37..41 'A(n)': A<i32> | ||
183 | 39..40 'n': &i32 | ||
184 | 44..49 '&A(1)': &A<i32> | ||
185 | 45..46 'A': A<i32>(i32) -> A<i32> | ||
186 | 45..49 'A(1)': A<i32> | ||
187 | 47..48 '1': i32 | ||
188 | 59..63 'A(n)': A<i32> | ||
189 | 61..62 'n': &mut i32 | ||
190 | 66..75 '&mut A(1)': &mut A<i32> | ||
191 | 71..72 'A': A<i32>(i32) -> A<i32> | ||
192 | 71..75 'A(1)': A<i32> | ||
193 | 73..74 '1': i32 | ||
194 | "#]], | ||
195 | ); | ||
196 | } | ||
197 | |||
198 | #[test] | ||
199 | fn infer_pattern_match_ergonomics_ref() { | ||
200 | mark::check!(match_ergonomics_ref); | ||
201 | check_infer( | ||
202 | r#" | ||
203 | fn test() { | ||
204 | let v = &(1, &2); | ||
205 | let (_, &w) = v; | ||
206 | } | ||
207 | "#, | ||
208 | expect![[r#" | ||
209 | 10..56 '{ ...= v; }': () | ||
210 | 20..21 'v': &(i32, &i32) | ||
211 | 24..32 '&(1, &2)': &(i32, &i32) | ||
212 | 25..32 '(1, &2)': (i32, &i32) | ||
213 | 26..27 '1': i32 | ||
214 | 29..31 '&2': &i32 | ||
215 | 30..31 '2': i32 | ||
216 | 42..49 '(_, &w)': (i32, &i32) | ||
217 | 43..44 '_': i32 | ||
218 | 46..48 '&w': &i32 | ||
219 | 47..48 'w': i32 | ||
220 | 52..53 'v': &(i32, &i32) | ||
221 | "#]], | ||
222 | ); | ||
223 | } | ||
224 | |||
225 | #[test] | ||
226 | fn infer_pattern_match_slice() { | ||
227 | check_infer( | ||
228 | r#" | ||
229 | fn test() { | ||
230 | let slice: &[f64] = &[0.0]; | ||
231 | match slice { | ||
232 | &[] => {}, | ||
233 | &[a] => { | ||
234 | a; | ||
235 | }, | ||
236 | &[b, c] => { | ||
237 | b; | ||
238 | c; | ||
239 | } | ||
240 | _ => {} | ||
241 | } | ||
242 | } | ||
243 | "#, | ||
244 | expect![[r#" | ||
245 | 10..209 '{ ... } }': () | ||
246 | 20..25 'slice': &[f64] | ||
247 | 36..42 '&[0.0]': &[f64; _] | ||
248 | 37..42 '[0.0]': [f64; _] | ||
249 | 38..41 '0.0': f64 | ||
250 | 48..207 'match ... }': () | ||
251 | 54..59 'slice': &[f64] | ||
252 | 70..73 '&[]': &[f64] | ||
253 | 71..73 '[]': [f64] | ||
254 | 77..79 '{}': () | ||
255 | 89..93 '&[a]': &[f64] | ||
256 | 90..93 '[a]': [f64] | ||
257 | 91..92 'a': f64 | ||
258 | 97..123 '{ ... }': () | ||
259 | 111..112 'a': f64 | ||
260 | 133..140 '&[b, c]': &[f64] | ||
261 | 134..140 '[b, c]': [f64] | ||
262 | 135..136 'b': f64 | ||
263 | 138..139 'c': f64 | ||
264 | 144..185 '{ ... }': () | ||
265 | 158..159 'b': f64 | ||
266 | 173..174 'c': f64 | ||
267 | 194..195 '_': &[f64] | ||
268 | 199..201 '{}': () | ||
269 | "#]], | ||
270 | ); | ||
271 | } | ||
272 | |||
273 | #[test] | ||
274 | fn infer_pattern_match_string_literal() { | ||
275 | check_infer_with_mismatches( | ||
276 | r#" | ||
277 | fn test() { | ||
278 | let s: &str = "hello"; | ||
279 | match s { | ||
280 | "hello" => {} | ||
281 | _ => {} | ||
282 | } | ||
283 | } | ||
284 | "#, | ||
285 | expect![[r#" | ||
286 | 10..98 '{ ... } }': () | ||
287 | 20..21 's': &str | ||
288 | 30..37 '"hello"': &str | ||
289 | 43..96 'match ... }': () | ||
290 | 49..50 's': &str | ||
291 | 61..68 '"hello"': &str | ||
292 | 61..68 '"hello"': &str | ||
293 | 72..74 '{}': () | ||
294 | 83..84 '_': &str | ||
295 | 88..90 '{}': () | ||
296 | "#]], | ||
297 | ); | ||
298 | } | ||
299 | |||
300 | #[test] | ||
301 | fn infer_pattern_match_or() { | ||
302 | check_infer_with_mismatches( | ||
303 | r#" | ||
304 | fn test() { | ||
305 | let s: &str = "hello"; | ||
306 | match s { | ||
307 | "hello" | "world" => {} | ||
308 | _ => {} | ||
309 | } | ||
310 | } | ||
311 | "#, | ||
312 | expect![[r#" | ||
313 | 10..108 '{ ... } }': () | ||
314 | 20..21 's': &str | ||
315 | 30..37 '"hello"': &str | ||
316 | 43..106 'match ... }': () | ||
317 | 49..50 's': &str | ||
318 | 61..68 '"hello"': &str | ||
319 | 61..68 '"hello"': &str | ||
320 | 61..78 '"hello...world"': &str | ||
321 | 71..78 '"world"': &str | ||
322 | 71..78 '"world"': &str | ||
323 | 82..84 '{}': () | ||
324 | 93..94 '_': &str | ||
325 | 98..100 '{}': () | ||
326 | "#]], | ||
327 | ); | ||
328 | } | ||
329 | |||
330 | #[test] | ||
331 | fn infer_pattern_match_arr() { | ||
332 | check_infer( | ||
333 | r#" | ||
334 | fn test() { | ||
335 | let arr: [f64; 2] = [0.0, 1.0]; | ||
336 | match arr { | ||
337 | [1.0, a] => { | ||
338 | a; | ||
339 | }, | ||
340 | [b, c] => { | ||
341 | b; | ||
342 | c; | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | "#, | ||
347 | expect![[r#" | ||
348 | 10..179 '{ ... } }': () | ||
349 | 20..23 'arr': [f64; _] | ||
350 | 36..46 '[0.0, 1.0]': [f64; _] | ||
351 | 37..40 '0.0': f64 | ||
352 | 42..45 '1.0': f64 | ||
353 | 52..177 'match ... }': () | ||
354 | 58..61 'arr': [f64; _] | ||
355 | 72..80 '[1.0, a]': [f64; _] | ||
356 | 73..76 '1.0': f64 | ||
357 | 73..76 '1.0': f64 | ||
358 | 78..79 'a': f64 | ||
359 | 84..110 '{ ... }': () | ||
360 | 98..99 'a': f64 | ||
361 | 120..126 '[b, c]': [f64; _] | ||
362 | 121..122 'b': f64 | ||
363 | 124..125 'c': f64 | ||
364 | 130..171 '{ ... }': () | ||
365 | 144..145 'b': f64 | ||
366 | 159..160 'c': f64 | ||
367 | "#]], | ||
368 | ); | ||
369 | } | ||
370 | |||
371 | #[test] | ||
372 | fn infer_adt_pattern() { | ||
373 | check_infer( | ||
374 | r#" | ||
375 | enum E { | ||
376 | A { x: usize }, | ||
377 | B | ||
378 | } | ||
379 | |||
380 | struct S(u32, E); | ||
381 | |||
382 | fn test() { | ||
383 | let e = E::A { x: 3 }; | ||
384 | |||
385 | let S(y, z) = foo; | ||
386 | let E::A { x: new_var } = e; | ||
387 | |||
388 | match e { | ||
389 | E::A { x } => x, | ||
390 | E::B if foo => 1, | ||
391 | E::B => 10, | ||
392 | }; | ||
393 | |||
394 | let ref d @ E::A { .. } = e; | ||
395 | d; | ||
396 | } | ||
397 | "#, | ||
398 | expect![[r#" | ||
399 | 67..288 '{ ... d; }': () | ||
400 | 77..78 'e': E | ||
401 | 81..94 'E::A { x: 3 }': E | ||
402 | 91..92 '3': usize | ||
403 | 105..112 'S(y, z)': S | ||
404 | 107..108 'y': u32 | ||
405 | 110..111 'z': E | ||
406 | 115..118 'foo': S | ||
407 | 128..147 'E::A {..._var }': E | ||
408 | 138..145 'new_var': usize | ||
409 | 150..151 'e': E | ||
410 | 158..244 'match ... }': usize | ||
411 | 164..165 'e': E | ||
412 | 176..186 'E::A { x }': E | ||
413 | 183..184 'x': usize | ||
414 | 190..191 'x': usize | ||
415 | 201..205 'E::B': E | ||
416 | 209..212 'foo': bool | ||
417 | 216..217 '1': usize | ||
418 | 227..231 'E::B': E | ||
419 | 235..237 '10': usize | ||
420 | 255..274 'ref d ...{ .. }': &E | ||
421 | 263..274 'E::A { .. }': E | ||
422 | 277..278 'e': E | ||
423 | 284..285 'd': &E | ||
424 | "#]], | ||
425 | ); | ||
426 | } | ||
427 | |||
428 | #[test] | ||
429 | fn enum_variant_through_self_in_pattern() { | ||
430 | check_infer( | ||
431 | r#" | ||
432 | enum E { | ||
433 | A { x: usize }, | ||
434 | B(usize), | ||
435 | C | ||
436 | } | ||
437 | |||
438 | impl E { | ||
439 | fn test() { | ||
440 | match (loop {}) { | ||
441 | Self::A { x } => { x; }, | ||
442 | Self::B(x) => { x; }, | ||
443 | Self::C => {}, | ||
444 | }; | ||
445 | } | ||
446 | } | ||
447 | "#, | ||
448 | expect![[r#" | ||
449 | 75..217 '{ ... }': () | ||
450 | 85..210 'match ... }': () | ||
451 | 92..99 'loop {}': ! | ||
452 | 97..99 '{}': () | ||
453 | 115..128 'Self::A { x }': E | ||
454 | 125..126 'x': usize | ||
455 | 132..138 '{ x; }': () | ||
456 | 134..135 'x': usize | ||
457 | 152..162 'Self::B(x)': E | ||
458 | 160..161 'x': usize | ||
459 | 166..172 '{ x; }': () | ||
460 | 168..169 'x': usize | ||
461 | 186..193 'Self::C': E | ||
462 | 197..199 '{}': () | ||
463 | "#]], | ||
464 | ); | ||
465 | } | ||
466 | |||
467 | #[test] | ||
468 | fn infer_generics_in_patterns() { | ||
469 | check_infer( | ||
470 | r#" | ||
471 | struct A<T> { | ||
472 | x: T, | ||
473 | } | ||
474 | |||
475 | enum Option<T> { | ||
476 | Some(T), | ||
477 | None, | ||
478 | } | ||
479 | |||
480 | fn test(a1: A<u32>, o: Option<u64>) { | ||
481 | let A { x: x2 } = a1; | ||
482 | let A::<i64> { x: x3 } = A { x: 1 }; | ||
483 | match o { | ||
484 | Option::Some(t) => t, | ||
485 | _ => 1, | ||
486 | }; | ||
487 | } | ||
488 | "#, | ||
489 | expect![[r#" | ||
490 | 78..80 'a1': A<u32> | ||
491 | 90..91 'o': Option<u64> | ||
492 | 106..243 '{ ... }; }': () | ||
493 | 116..127 'A { x: x2 }': A<u32> | ||
494 | 123..125 'x2': u32 | ||
495 | 130..132 'a1': A<u32> | ||
496 | 142..160 'A::<i6...: x3 }': A<i64> | ||
497 | 156..158 'x3': i64 | ||
498 | 163..173 'A { x: 1 }': A<i64> | ||
499 | 170..171 '1': i64 | ||
500 | 179..240 'match ... }': u64 | ||
501 | 185..186 'o': Option<u64> | ||
502 | 197..212 'Option::Some(t)': Option<u64> | ||
503 | 210..211 't': u64 | ||
504 | 216..217 't': u64 | ||
505 | 227..228 '_': Option<u64> | ||
506 | 232..233 '1': u64 | ||
507 | "#]], | ||
508 | ); | ||
509 | } | ||
510 | |||
511 | #[test] | ||
512 | fn infer_const_pattern() { | ||
513 | check_infer_with_mismatches( | ||
514 | r#" | ||
515 | enum Option<T> { None } | ||
516 | use Option::None; | ||
517 | struct Foo; | ||
518 | const Bar: usize = 1; | ||
519 | |||
520 | fn test() { | ||
521 | let a: Option<u32> = None; | ||
522 | let b: Option<i64> = match a { | ||
523 | None => None, | ||
524 | }; | ||
525 | let _: () = match () { Foo => Foo }; // Expected mismatch | ||
526 | let _: () = match () { Bar => Bar }; // Expected mismatch | ||
527 | } | ||
528 | "#, | ||
529 | expect![[r#" | ||
530 | 73..74 '1': usize | ||
531 | 87..309 '{ ...atch }': () | ||
532 | 97..98 'a': Option<u32> | ||
533 | 114..118 'None': Option<u32> | ||
534 | 128..129 'b': Option<i64> | ||
535 | 145..182 'match ... }': Option<i64> | ||
536 | 151..152 'a': Option<u32> | ||
537 | 163..167 'None': Option<u32> | ||
538 | 171..175 'None': Option<i64> | ||
539 | 192..193 '_': () | ||
540 | 200..223 'match ... Foo }': Foo | ||
541 | 206..208 '()': () | ||
542 | 211..214 'Foo': Foo | ||
543 | 218..221 'Foo': Foo | ||
544 | 254..255 '_': () | ||
545 | 262..285 'match ... Bar }': usize | ||
546 | 268..270 '()': () | ||
547 | 273..276 'Bar': usize | ||
548 | 280..283 'Bar': usize | ||
549 | 200..223: expected (), got Foo | ||
550 | 262..285: expected (), got usize | ||
551 | "#]], | ||
552 | ); | ||
553 | } | ||
554 | |||
555 | #[test] | ||
556 | fn infer_guard() { | ||
557 | check_infer( | ||
558 | r#" | ||
559 | struct S; | ||
560 | impl S { fn foo(&self) -> bool { false } } | ||
561 | |||
562 | fn main() { | ||
563 | match S { | ||
564 | s if s.foo() => (), | ||
565 | } | ||
566 | } | ||
567 | "#, | ||
568 | expect![[r#" | ||
569 | 27..31 'self': &S | ||
570 | 41..50 '{ false }': bool | ||
571 | 43..48 'false': bool | ||
572 | 64..115 '{ ... } }': () | ||
573 | 70..113 'match ... }': () | ||
574 | 76..77 'S': S | ||
575 | 88..89 's': S | ||
576 | 93..94 's': S | ||
577 | 93..100 's.foo()': bool | ||
578 | 104..106 '()': () | ||
579 | "#]], | ||
580 | ) | ||
581 | } | ||
582 | |||
583 | #[test] | ||
584 | fn match_ergonomics_in_closure_params() { | ||
585 | check_infer( | ||
586 | r#" | ||
587 | #[lang = "fn_once"] | ||
588 | trait FnOnce<Args> { | ||
589 | type Output; | ||
590 | } | ||
591 | |||
592 | fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} } | ||
593 | |||
594 | fn test() { | ||
595 | foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics | ||
596 | foo(&(1, "a"), |(x, y)| x); | ||
597 | } | ||
598 | "#, | ||
599 | expect![[r#" | ||
600 | 93..94 't': T | ||
601 | 99..100 'f': F | ||
602 | 110..121 '{ loop {} }': U | ||
603 | 112..119 'loop {}': ! | ||
604 | 117..119 '{}': () | ||
605 | 133..232 '{ ... x); }': () | ||
606 | 139..142 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32 | ||
607 | 139..166 'foo(&(...y)| x)': i32 | ||
608 | 143..152 '&(1, "a")': &(i32, &str) | ||
609 | 144..152 '(1, "a")': (i32, &str) | ||
610 | 145..146 '1': i32 | ||
611 | 148..151 '"a"': &str | ||
612 | 154..165 '|&(x, y)| x': |&(i32, &str)| -> i32 | ||
613 | 155..162 '&(x, y)': &(i32, &str) | ||
614 | 156..162 '(x, y)': (i32, &str) | ||
615 | 157..158 'x': i32 | ||
616 | 160..161 'y': &str | ||
617 | 164..165 'x': i32 | ||
618 | 203..206 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32 | ||
619 | 203..229 'foo(&(...y)| x)': &i32 | ||
620 | 207..216 '&(1, "a")': &(i32, &str) | ||
621 | 208..216 '(1, "a")': (i32, &str) | ||
622 | 209..210 '1': i32 | ||
623 | 212..215 '"a"': &str | ||
624 | 218..228 '|(x, y)| x': |&(i32, &str)| -> &i32 | ||
625 | 219..225 '(x, y)': (i32, &str) | ||
626 | 220..221 'x': &i32 | ||
627 | 223..224 'y': &&str | ||
628 | 227..228 'x': &i32 | ||
629 | "#]], | ||
630 | ); | ||
631 | } | ||
632 | |||
633 | #[test] | ||
634 | fn slice_tail_pattern() { | ||
635 | check_infer( | ||
636 | r#" | ||
637 | fn foo(params: &[i32]) { | ||
638 | match params { | ||
639 | [head, tail @ ..] => { | ||
640 | } | ||
641 | } | ||
642 | } | ||
643 | "#, | ||
644 | expect![[r#" | ||
645 | 7..13 'params': &[i32] | ||
646 | 23..92 '{ ... } }': () | ||
647 | 29..90 'match ... }': () | ||
648 | 35..41 'params': &[i32] | ||
649 | 52..69 '[head,... @ ..]': [i32] | ||
650 | 53..57 'head': &i32 | ||
651 | 59..68 'tail @ ..': &[i32] | ||
652 | 66..68 '..': [i32] | ||
653 | 73..84 '{ }': () | ||
654 | "#]], | ||
655 | ); | ||
656 | } | ||
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs new file mode 100644 index 000000000..b9ab0f357 --- /dev/null +++ b/crates/hir_ty/src/tests/regression.rs | |||
@@ -0,0 +1,842 @@ | |||
1 | use expect::expect; | ||
2 | use test_utils::mark; | ||
3 | |||
4 | use super::{check_infer, check_types}; | ||
5 | |||
6 | #[test] | ||
7 | fn bug_484() { | ||
8 | check_infer( | ||
9 | r#" | ||
10 | fn test() { | ||
11 | let x = if true {}; | ||
12 | } | ||
13 | "#, | ||
14 | expect![[r#" | ||
15 | 10..37 '{ ... {}; }': () | ||
16 | 20..21 'x': () | ||
17 | 24..34 'if true {}': () | ||
18 | 27..31 'true': bool | ||
19 | 32..34 '{}': () | ||
20 | "#]], | ||
21 | ); | ||
22 | } | ||
23 | |||
24 | #[test] | ||
25 | fn no_panic_on_field_of_enum() { | ||
26 | check_infer( | ||
27 | r#" | ||
28 | enum X {} | ||
29 | |||
30 | fn test(x: X) { | ||
31 | x.some_field; | ||
32 | } | ||
33 | "#, | ||
34 | expect![[r#" | ||
35 | 19..20 'x': X | ||
36 | 25..46 '{ ...eld; }': () | ||
37 | 31..32 'x': X | ||
38 | 31..43 'x.some_field': {unknown} | ||
39 | "#]], | ||
40 | ); | ||
41 | } | ||
42 | |||
43 | #[test] | ||
44 | fn bug_585() { | ||
45 | check_infer( | ||
46 | r#" | ||
47 | fn test() { | ||
48 | X {}; | ||
49 | match x { | ||
50 | A::B {} => (), | ||
51 | A::Y() => (), | ||
52 | } | ||
53 | } | ||
54 | "#, | ||
55 | expect![[r#" | ||
56 | 10..88 '{ ... } }': () | ||
57 | 16..20 'X {}': {unknown} | ||
58 | 26..86 'match ... }': () | ||
59 | 32..33 'x': {unknown} | ||
60 | 44..51 'A::B {}': {unknown} | ||
61 | 55..57 '()': () | ||
62 | 67..73 'A::Y()': {unknown} | ||
63 | 77..79 '()': () | ||
64 | "#]], | ||
65 | ); | ||
66 | } | ||
67 | |||
68 | #[test] | ||
69 | fn bug_651() { | ||
70 | check_infer( | ||
71 | r#" | ||
72 | fn quux() { | ||
73 | let y = 92; | ||
74 | 1 + y; | ||
75 | } | ||
76 | "#, | ||
77 | expect![[r#" | ||
78 | 10..40 '{ ...+ y; }': () | ||
79 | 20..21 'y': i32 | ||
80 | 24..26 '92': i32 | ||
81 | 32..33 '1': i32 | ||
82 | 32..37 '1 + y': i32 | ||
83 | 36..37 'y': i32 | ||
84 | "#]], | ||
85 | ); | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn recursive_vars() { | ||
90 | mark::check!(type_var_cycles_resolve_completely); | ||
91 | mark::check!(type_var_cycles_resolve_as_possible); | ||
92 | check_infer( | ||
93 | r#" | ||
94 | fn test() { | ||
95 | let y = unknown; | ||
96 | [y, &y]; | ||
97 | } | ||
98 | "#, | ||
99 | expect![[r#" | ||
100 | 10..47 '{ ...&y]; }': () | ||
101 | 20..21 'y': &{unknown} | ||
102 | 24..31 'unknown': &{unknown} | ||
103 | 37..44 '[y, &y]': [&&{unknown}; _] | ||
104 | 38..39 'y': &{unknown} | ||
105 | 41..43 '&y': &&{unknown} | ||
106 | 42..43 'y': &{unknown} | ||
107 | "#]], | ||
108 | ); | ||
109 | } | ||
110 | |||
111 | #[test] | ||
112 | fn recursive_vars_2() { | ||
113 | check_infer( | ||
114 | r#" | ||
115 | fn test() { | ||
116 | let x = unknown; | ||
117 | let y = unknown; | ||
118 | [(x, y), (&y, &x)]; | ||
119 | } | ||
120 | "#, | ||
121 | expect![[r#" | ||
122 | 10..79 '{ ...x)]; }': () | ||
123 | 20..21 'x': &&{unknown} | ||
124 | 24..31 'unknown': &&{unknown} | ||
125 | 41..42 'y': &&{unknown} | ||
126 | 45..52 'unknown': &&{unknown} | ||
127 | 58..76 '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown}); _] | ||
128 | 59..65 '(x, y)': (&&&{unknown}, &&&{unknown}) | ||
129 | 60..61 'x': &&{unknown} | ||
130 | 63..64 'y': &&{unknown} | ||
131 | 67..75 '(&y, &x)': (&&&{unknown}, &&&{unknown}) | ||
132 | 68..70 '&y': &&&{unknown} | ||
133 | 69..70 'y': &&{unknown} | ||
134 | 72..74 '&x': &&&{unknown} | ||
135 | 73..74 'x': &&{unknown} | ||
136 | "#]], | ||
137 | ); | ||
138 | } | ||
139 | |||
140 | #[test] | ||
141 | fn infer_std_crash_1() { | ||
142 | // caused stack overflow, taken from std | ||
143 | check_infer( | ||
144 | r#" | ||
145 | enum Maybe<T> { | ||
146 | Real(T), | ||
147 | Fake, | ||
148 | } | ||
149 | |||
150 | fn write() { | ||
151 | match something_unknown { | ||
152 | Maybe::Real(ref mut something) => (), | ||
153 | } | ||
154 | } | ||
155 | "#, | ||
156 | expect![[r#" | ||
157 | 53..138 '{ ... } }': () | ||
158 | 59..136 'match ... }': () | ||
159 | 65..82 'someth...nknown': Maybe<{unknown}> | ||
160 | 93..123 'Maybe:...thing)': Maybe<{unknown}> | ||
161 | 105..122 'ref mu...ething': &mut {unknown} | ||
162 | 127..129 '()': () | ||
163 | "#]], | ||
164 | ); | ||
165 | } | ||
166 | |||
167 | #[test] | ||
168 | fn infer_std_crash_2() { | ||
169 | mark::check!(type_var_resolves_to_int_var); | ||
170 | // caused "equating two type variables, ...", taken from std | ||
171 | check_infer( | ||
172 | r#" | ||
173 | fn test_line_buffer() { | ||
174 | &[0, b'\n', 1, b'\n']; | ||
175 | } | ||
176 | "#, | ||
177 | expect![[r#" | ||
178 | 22..52 '{ ...n']; }': () | ||
179 | 28..49 '&[0, b...b'\n']': &[u8; _] | ||
180 | 29..49 '[0, b'...b'\n']': [u8; _] | ||
181 | 30..31 '0': u8 | ||
182 | 33..38 'b'\n'': u8 | ||
183 | 40..41 '1': u8 | ||
184 | 43..48 'b'\n'': u8 | ||
185 | "#]], | ||
186 | ); | ||
187 | } | ||
188 | |||
189 | #[test] | ||
190 | fn infer_std_crash_3() { | ||
191 | // taken from rustc | ||
192 | check_infer( | ||
193 | r#" | ||
194 | pub fn compute() { | ||
195 | match nope!() { | ||
196 | SizeSkeleton::Pointer { non_zero: true, tail } => {} | ||
197 | } | ||
198 | } | ||
199 | "#, | ||
200 | expect![[r#" | ||
201 | 17..107 '{ ... } }': () | ||
202 | 23..105 'match ... }': () | ||
203 | 29..36 'nope!()': {unknown} | ||
204 | 47..93 'SizeSk...tail }': {unknown} | ||
205 | 81..85 'true': bool | ||
206 | 81..85 'true': bool | ||
207 | 87..91 'tail': {unknown} | ||
208 | 97..99 '{}': () | ||
209 | "#]], | ||
210 | ); | ||
211 | } | ||
212 | |||
213 | #[test] | ||
214 | fn infer_std_crash_4() { | ||
215 | // taken from rustc | ||
216 | check_infer( | ||
217 | r#" | ||
218 | pub fn primitive_type() { | ||
219 | match *self { | ||
220 | BorrowedRef { type_: Primitive(p), ..} => {}, | ||
221 | } | ||
222 | } | ||
223 | "#, | ||
224 | expect![[r#" | ||
225 | 24..105 '{ ... } }': () | ||
226 | 30..103 'match ... }': () | ||
227 | 36..41 '*self': {unknown} | ||
228 | 37..41 'self': {unknown} | ||
229 | 52..90 'Borrow...), ..}': {unknown} | ||
230 | 73..85 'Primitive(p)': {unknown} | ||
231 | 83..84 'p': {unknown} | ||
232 | 94..96 '{}': () | ||
233 | "#]], | ||
234 | ); | ||
235 | } | ||
236 | |||
237 | #[test] | ||
238 | fn infer_std_crash_5() { | ||
239 | // taken from rustc | ||
240 | check_infer( | ||
241 | r#" | ||
242 | fn extra_compiler_flags() { | ||
243 | for content in doesnt_matter { | ||
244 | let name = if doesnt_matter { | ||
245 | first | ||
246 | } else { | ||
247 | &content | ||
248 | }; | ||
249 | |||
250 | let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { | ||
251 | name | ||
252 | } else { | ||
253 | content | ||
254 | }; | ||
255 | } | ||
256 | } | ||
257 | "#, | ||
258 | expect![[r#" | ||
259 | 26..322 '{ ... } }': () | ||
260 | 32..320 'for co... }': () | ||
261 | 36..43 'content': &{unknown} | ||
262 | 47..60 'doesnt_matter': {unknown} | ||
263 | 61..320 '{ ... }': () | ||
264 | 75..79 'name': &&{unknown} | ||
265 | 82..166 'if doe... }': &&{unknown} | ||
266 | 85..98 'doesnt_matter': bool | ||
267 | 99..128 '{ ... }': &&{unknown} | ||
268 | 113..118 'first': &&{unknown} | ||
269 | 134..166 '{ ... }': &&{unknown} | ||
270 | 148..156 '&content': &&{unknown} | ||
271 | 149..156 'content': &{unknown} | ||
272 | 181..188 'content': &{unknown} | ||
273 | 191..313 'if ICE... }': &{unknown} | ||
274 | 194..231 'ICE_RE..._VALUE': {unknown} | ||
275 | 194..247 'ICE_RE...&name)': bool | ||
276 | 241..246 '&name': &&&{unknown} | ||
277 | 242..246 'name': &&{unknown} | ||
278 | 248..276 '{ ... }': &&{unknown} | ||
279 | 262..266 'name': &&{unknown} | ||
280 | 282..313 '{ ... }': &{unknown} | ||
281 | 296..303 'content': &{unknown} | ||
282 | "#]], | ||
283 | ); | ||
284 | } | ||
285 | |||
286 | #[test] | ||
287 | fn infer_nested_generics_crash() { | ||
288 | // another crash found typechecking rustc | ||
289 | check_infer( | ||
290 | r#" | ||
291 | struct Canonical<V> { | ||
292 | value: V, | ||
293 | } | ||
294 | struct QueryResponse<V> { | ||
295 | value: V, | ||
296 | } | ||
297 | fn test<R>(query_response: Canonical<QueryResponse<R>>) { | ||
298 | &query_response.value; | ||
299 | } | ||
300 | "#, | ||
301 | expect![[r#" | ||
302 | 91..105 'query_response': Canonical<QueryResponse<R>> | ||
303 | 136..166 '{ ...lue; }': () | ||
304 | 142..163 '&query....value': &QueryResponse<R> | ||
305 | 143..157 'query_response': Canonical<QueryResponse<R>> | ||
306 | 143..163 'query_....value': QueryResponse<R> | ||
307 | "#]], | ||
308 | ); | ||
309 | } | ||
310 | |||
311 | #[test] | ||
312 | fn infer_paren_macro_call() { | ||
313 | check_infer( | ||
314 | r#" | ||
315 | macro_rules! bar { () => {0u32} } | ||
316 | fn test() { | ||
317 | let a = (bar!()); | ||
318 | } | ||
319 | "#, | ||
320 | expect![[r#" | ||
321 | !0..4 '0u32': u32 | ||
322 | 44..69 '{ ...()); }': () | ||
323 | 54..55 'a': u32 | ||
324 | "#]], | ||
325 | ); | ||
326 | } | ||
327 | |||
328 | #[test] | ||
329 | fn bug_1030() { | ||
330 | check_infer( | ||
331 | r#" | ||
332 | struct HashSet<T, H>; | ||
333 | struct FxHasher; | ||
334 | type FxHashSet<T> = HashSet<T, FxHasher>; | ||
335 | |||
336 | impl<T, H> HashSet<T, H> { | ||
337 | fn default() -> HashSet<T, H> {} | ||
338 | } | ||
339 | |||
340 | pub fn main_loop() { | ||
341 | FxHashSet::default(); | ||
342 | } | ||
343 | "#, | ||
344 | expect![[r#" | ||
345 | 143..145 '{}': () | ||
346 | 168..197 '{ ...t(); }': () | ||
347 | 174..192 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<{unknown}, FxHasher> | ||
348 | 174..194 'FxHash...ault()': HashSet<{unknown}, FxHasher> | ||
349 | "#]], | ||
350 | ); | ||
351 | } | ||
352 | |||
353 | #[test] | ||
354 | fn issue_2669() { | ||
355 | check_infer( | ||
356 | r#" | ||
357 | trait A {} | ||
358 | trait Write {} | ||
359 | struct Response<T> {} | ||
360 | |||
361 | trait D { | ||
362 | fn foo(); | ||
363 | } | ||
364 | |||
365 | impl<T:A> D for Response<T> { | ||
366 | fn foo() { | ||
367 | end(); | ||
368 | fn end<W: Write>() { | ||
369 | let _x: T = loop {}; | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | "#, | ||
374 | expect![[r#" | ||
375 | 119..214 '{ ... }': () | ||
376 | 129..132 'end': fn end<{unknown}>() | ||
377 | 129..134 'end()': () | ||
378 | 163..208 '{ ... }': () | ||
379 | 181..183 '_x': ! | ||
380 | 190..197 'loop {}': ! | ||
381 | 195..197 '{}': () | ||
382 | "#]], | ||
383 | ) | ||
384 | } | ||
385 | |||
386 | #[test] | ||
387 | fn issue_2705() { | ||
388 | check_infer( | ||
389 | r#" | ||
390 | trait Trait {} | ||
391 | fn test() { | ||
392 | <Trait<u32>>::foo() | ||
393 | } | ||
394 | "#, | ||
395 | expect![[r#" | ||
396 | 25..52 '{ ...oo() }': () | ||
397 | 31..48 '<Trait...>::foo': {unknown} | ||
398 | 31..50 '<Trait...:foo()': () | ||
399 | "#]], | ||
400 | ); | ||
401 | } | ||
402 | |||
403 | #[test] | ||
404 | fn issue_2683_chars_impl() { | ||
405 | check_types( | ||
406 | r#" | ||
407 | //- /main.rs crate:main deps:std | ||
408 | fn test() { | ||
409 | let chars: std::str::Chars<'_>; | ||
410 | (chars.next(), chars.nth(1)); | ||
411 | } //^ (Option<char>, Option<char>) | ||
412 | |||
413 | //- /std.rs crate:std | ||
414 | #[prelude_import] | ||
415 | use prelude::*; | ||
416 | |||
417 | pub mod prelude { | ||
418 | pub use crate::iter::Iterator; | ||
419 | pub use crate::option::Option; | ||
420 | } | ||
421 | |||
422 | pub mod iter { | ||
423 | pub use self::traits::Iterator; | ||
424 | pub mod traits { | ||
425 | pub use self::iterator::Iterator; | ||
426 | |||
427 | pub mod iterator { | ||
428 | pub trait Iterator { | ||
429 | type Item; | ||
430 | fn next(&mut self) -> Option<Self::Item>; | ||
431 | fn nth(&mut self, n: usize) -> Option<Self::Item> {} | ||
432 | } | ||
433 | } | ||
434 | } | ||
435 | } | ||
436 | |||
437 | pub mod option { | ||
438 | pub enum Option<T> {} | ||
439 | } | ||
440 | |||
441 | pub mod str { | ||
442 | pub struct Chars<'a> {} | ||
443 | impl<'a> Iterator for Chars<'a> { | ||
444 | type Item = char; | ||
445 | fn next(&mut self) -> Option<char> {} | ||
446 | } | ||
447 | } | ||
448 | "#, | ||
449 | ); | ||
450 | } | ||
451 | |||
452 | #[test] | ||
453 | fn issue_3642_bad_macro_stackover() { | ||
454 | check_types( | ||
455 | r#" | ||
456 | #[macro_export] | ||
457 | macro_rules! match_ast { | ||
458 | (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; | ||
459 | |||
460 | (match ($node:expr) { | ||
461 | $( ast::$ast:ident($it:ident) => $res:expr, )* | ||
462 | _ => $catch_all:expr $(,)? | ||
463 | }) => {{ | ||
464 | $( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )* | ||
465 | { $catch_all } | ||
466 | }}; | ||
467 | } | ||
468 | |||
469 | fn main() { | ||
470 | let anchor = match_ast! { | ||
471 | //^ () | ||
472 | match parent { | ||
473 | as => {}, | ||
474 | _ => return None | ||
475 | } | ||
476 | }; | ||
477 | }"#, | ||
478 | ); | ||
479 | } | ||
480 | |||
481 | #[test] | ||
482 | fn issue_3999_slice() { | ||
483 | check_infer( | ||
484 | r#" | ||
485 | fn foo(params: &[usize]) { | ||
486 | match params { | ||
487 | [ps @ .., _] => {} | ||
488 | } | ||
489 | } | ||
490 | "#, | ||
491 | expect![[r#" | ||
492 | 7..13 'params': &[usize] | ||
493 | 25..80 '{ ... } }': () | ||
494 | 31..78 'match ... }': () | ||
495 | 37..43 'params': &[usize] | ||
496 | 54..66 '[ps @ .., _]': [usize] | ||
497 | 55..62 'ps @ ..': &[usize] | ||
498 | 60..62 '..': [usize] | ||
499 | 64..65 '_': usize | ||
500 | 70..72 '{}': () | ||
501 | "#]], | ||
502 | ); | ||
503 | } | ||
504 | |||
505 | #[test] | ||
506 | fn issue_3999_struct() { | ||
507 | // rust-analyzer should not panic on seeing this malformed | ||
508 | // record pattern. | ||
509 | check_infer( | ||
510 | r#" | ||
511 | struct Bar { | ||
512 | a: bool, | ||
513 | } | ||
514 | fn foo(b: Bar) { | ||
515 | match b { | ||
516 | Bar { a: .. } => {}, | ||
517 | } | ||
518 | } | ||
519 | "#, | ||
520 | expect![[r#" | ||
521 | 35..36 'b': Bar | ||
522 | 43..95 '{ ... } }': () | ||
523 | 49..93 'match ... }': () | ||
524 | 55..56 'b': Bar | ||
525 | 67..80 'Bar { a: .. }': Bar | ||
526 | 76..78 '..': bool | ||
527 | 84..86 '{}': () | ||
528 | "#]], | ||
529 | ); | ||
530 | } | ||
531 | |||
532 | #[test] | ||
533 | fn issue_4235_name_conflicts() { | ||
534 | check_infer( | ||
535 | r#" | ||
536 | struct FOO {} | ||
537 | static FOO:FOO = FOO {}; | ||
538 | |||
539 | impl FOO { | ||
540 | fn foo(&self) {} | ||
541 | } | ||
542 | |||
543 | fn main() { | ||
544 | let a = &FOO; | ||
545 | a.foo(); | ||
546 | } | ||
547 | "#, | ||
548 | expect![[r#" | ||
549 | 31..37 'FOO {}': FOO | ||
550 | 63..67 'self': &FOO | ||
551 | 69..71 '{}': () | ||
552 | 85..119 '{ ...o(); }': () | ||
553 | 95..96 'a': &FOO | ||
554 | 99..103 '&FOO': &FOO | ||
555 | 100..103 'FOO': FOO | ||
556 | 109..110 'a': &FOO | ||
557 | 109..116 'a.foo()': () | ||
558 | "#]], | ||
559 | ); | ||
560 | } | ||
561 | |||
562 | #[test] | ||
563 | fn issue_4465_dollar_crate_at_type() { | ||
564 | check_infer( | ||
565 | r#" | ||
566 | pub struct Foo {} | ||
567 | pub fn anything<T>() -> T { | ||
568 | loop {} | ||
569 | } | ||
570 | macro_rules! foo { | ||
571 | () => {{ | ||
572 | let r: $crate::Foo = anything(); | ||
573 | r | ||
574 | }}; | ||
575 | } | ||
576 | fn main() { | ||
577 | let _a = foo!(); | ||
578 | } | ||
579 | "#, | ||
580 | expect![[r#" | ||
581 | 44..59 '{ loop {} }': T | ||
582 | 50..57 'loop {}': ! | ||
583 | 55..57 '{}': () | ||
584 | !0..31 '{letr:...g();r}': Foo | ||
585 | !4..5 'r': Foo | ||
586 | !18..26 'anything': fn anything<Foo>() -> Foo | ||
587 | !18..28 'anything()': Foo | ||
588 | !29..30 'r': Foo | ||
589 | 163..187 '{ ...!(); }': () | ||
590 | 173..175 '_a': Foo | ||
591 | "#]], | ||
592 | ); | ||
593 | } | ||
594 | |||
595 | #[test] | ||
596 | fn issue_4053_diesel_where_clauses() { | ||
597 | check_infer( | ||
598 | r#" | ||
599 | trait BoxedDsl<DB> { | ||
600 | type Output; | ||
601 | fn internal_into_boxed(self) -> Self::Output; | ||
602 | } | ||
603 | |||
604 | struct SelectStatement<From, Select, Distinct, Where, Order, LimitOffset, GroupBy, Locking> { | ||
605 | order: Order, | ||
606 | } | ||
607 | |||
608 | trait QueryFragment<DB: Backend> {} | ||
609 | |||
610 | trait Into<T> { fn into(self) -> T; } | ||
611 | |||
612 | impl<F, S, D, W, O, LOf, DB> BoxedDsl<DB> | ||
613 | for SelectStatement<F, S, D, W, O, LOf, G> | ||
614 | where | ||
615 | O: Into<dyn QueryFragment<DB>>, | ||
616 | { | ||
617 | type Output = XXX; | ||
618 | |||
619 | fn internal_into_boxed(self) -> Self::Output { | ||
620 | self.order.into(); | ||
621 | } | ||
622 | } | ||
623 | "#, | ||
624 | expect![[r#" | ||
625 | 65..69 'self': Self | ||
626 | 267..271 'self': Self | ||
627 | 466..470 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> | ||
628 | 488..522 '{ ... }': () | ||
629 | 498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> | ||
630 | 498..508 'self.order': O | ||
631 | 498..515 'self.o...into()': dyn QueryFragment<DB> | ||
632 | "#]], | ||
633 | ); | ||
634 | } | ||
635 | |||
636 | #[test] | ||
637 | fn issue_4953() { | ||
638 | check_infer( | ||
639 | r#" | ||
640 | pub struct Foo(pub i64); | ||
641 | impl Foo { | ||
642 | fn test() -> Self { Self(0i64) } | ||
643 | } | ||
644 | "#, | ||
645 | expect![[r#" | ||
646 | 58..72 '{ Self(0i64) }': Foo | ||
647 | 60..64 'Self': Foo(i64) -> Foo | ||
648 | 60..70 'Self(0i64)': Foo | ||
649 | 65..69 '0i64': i64 | ||
650 | "#]], | ||
651 | ); | ||
652 | check_infer( | ||
653 | r#" | ||
654 | pub struct Foo<T>(pub T); | ||
655 | impl Foo<i64> { | ||
656 | fn test() -> Self { Self(0i64) } | ||
657 | } | ||
658 | "#, | ||
659 | expect![[r#" | ||
660 | 64..78 '{ Self(0i64) }': Foo<i64> | ||
661 | 66..70 'Self': Foo<i64>(i64) -> Foo<i64> | ||
662 | 66..76 'Self(0i64)': Foo<i64> | ||
663 | 71..75 '0i64': i64 | ||
664 | "#]], | ||
665 | ); | ||
666 | } | ||
667 | |||
668 | #[test] | ||
669 | fn issue_4931() { | ||
670 | check_infer( | ||
671 | r#" | ||
672 | trait Div<T> { | ||
673 | type Output; | ||
674 | } | ||
675 | |||
676 | trait CheckedDiv: Div<()> {} | ||
677 | |||
678 | trait PrimInt: CheckedDiv<Output = ()> { | ||
679 | fn pow(self); | ||
680 | } | ||
681 | |||
682 | fn check<T: PrimInt>(i: T) { | ||
683 | i.pow(); | ||
684 | } | ||
685 | "#, | ||
686 | expect![[r#" | ||
687 | 117..121 'self': Self | ||
688 | 148..149 'i': T | ||
689 | 154..170 '{ ...w(); }': () | ||
690 | 160..161 'i': T | ||
691 | 160..167 'i.pow()': () | ||
692 | "#]], | ||
693 | ); | ||
694 | } | ||
695 | |||
696 | #[test] | ||
697 | fn issue_4885() { | ||
698 | check_infer( | ||
699 | r#" | ||
700 | #[lang = "coerce_unsized"] | ||
701 | pub trait CoerceUnsized<T> {} | ||
702 | |||
703 | trait Future { | ||
704 | type Output; | ||
705 | } | ||
706 | trait Foo<R> { | ||
707 | type Bar; | ||
708 | } | ||
709 | fn foo<R, K>(key: &K) -> impl Future<Output = K::Bar> | ||
710 | where | ||
711 | K: Foo<R>, | ||
712 | { | ||
713 | bar(key) | ||
714 | } | ||
715 | fn bar<R, K>(key: &K) -> impl Future<Output = K::Bar> | ||
716 | where | ||
717 | K: Foo<R>, | ||
718 | { | ||
719 | } | ||
720 | "#, | ||
721 | expect![[r#" | ||
722 | 136..139 'key': &K | ||
723 | 198..214 '{ ...key) }': impl Future<Output = <K as Foo<R>>::Bar> | ||
724 | 204..207 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar> | ||
725 | 204..212 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar> | ||
726 | 208..211 'key': &K | ||
727 | 228..231 'key': &K | ||
728 | 290..293 '{ }': () | ||
729 | "#]], | ||
730 | ); | ||
731 | } | ||
732 | |||
733 | #[test] | ||
734 | fn issue_4800() { | ||
735 | check_infer( | ||
736 | r#" | ||
737 | trait Debug {} | ||
738 | |||
739 | struct Foo<T>; | ||
740 | |||
741 | type E1<T> = (T, T, T); | ||
742 | type E2<T> = E1<E1<E1<(T, T, T)>>>; | ||
743 | |||
744 | impl Debug for Foo<E2<()>> {} | ||
745 | |||
746 | struct Request; | ||
747 | |||
748 | pub trait Future { | ||
749 | type Output; | ||
750 | } | ||
751 | |||
752 | pub struct PeerSet<D>; | ||
753 | |||
754 | impl<D> Service<Request> for PeerSet<D> | ||
755 | where | ||
756 | D: Discover, | ||
757 | D::Key: Debug, | ||
758 | { | ||
759 | type Error = (); | ||
760 | type Future = dyn Future<Output = Self::Error>; | ||
761 | |||
762 | fn call(&mut self) -> Self::Future { | ||
763 | loop {} | ||
764 | } | ||
765 | } | ||
766 | |||
767 | pub trait Discover { | ||
768 | type Key; | ||
769 | } | ||
770 | |||
771 | pub trait Service<Request> { | ||
772 | type Error; | ||
773 | type Future: Future<Output = Self::Error>; | ||
774 | fn call(&mut self) -> Self::Future; | ||
775 | } | ||
776 | "#, | ||
777 | expect![[r#" | ||
778 | 379..383 'self': &mut PeerSet<D> | ||
779 | 401..424 '{ ... }': dyn Future<Output = ()> | ||
780 | 411..418 'loop {}': ! | ||
781 | 416..418 '{}': () | ||
782 | 575..579 'self': &mut Self | ||
783 | "#]], | ||
784 | ); | ||
785 | } | ||
786 | |||
787 | #[test] | ||
788 | fn issue_4966() { | ||
789 | check_infer( | ||
790 | r#" | ||
791 | pub trait IntoIterator { | ||
792 | type Item; | ||
793 | } | ||
794 | |||
795 | struct Repeat<A> { element: A } | ||
796 | |||
797 | struct Map<F> { f: F } | ||
798 | |||
799 | struct Vec<T> {} | ||
800 | |||
801 | #[lang = "deref"] | ||
802 | pub trait Deref { | ||
803 | type Target; | ||
804 | } | ||
805 | |||
806 | impl<T> Deref for Vec<T> { | ||
807 | type Target = [T]; | ||
808 | } | ||
809 | |||
810 | fn from_iter<A, T: IntoIterator<Item = A>>(iter: T) -> Vec<A> {} | ||
811 | |||
812 | fn main() { | ||
813 | let inner = Map { f: |_: &f64| 0.0 }; | ||
814 | |||
815 | let repeat = Repeat { element: inner }; | ||
816 | |||
817 | let vec = from_iter(repeat); | ||
818 | |||
819 | vec.foo_bar(); | ||
820 | } | ||
821 | "#, | ||
822 | expect![[r#" | ||
823 | 270..274 'iter': T | ||
824 | 289..291 '{}': () | ||
825 | 303..447 '{ ...r(); }': () | ||
826 | 313..318 'inner': Map<|&f64| -> f64> | ||
827 | 321..345 'Map { ... 0.0 }': Map<|&f64| -> f64> | ||
828 | 330..343 '|_: &f64| 0.0': |&f64| -> f64 | ||
829 | 331..332 '_': &f64 | ||
830 | 340..343 '0.0': f64 | ||
831 | 356..362 'repeat': Repeat<Map<|&f64| -> f64>> | ||
832 | 365..390 'Repeat...nner }': Repeat<Map<|&f64| -> f64>> | ||
833 | 383..388 'inner': Map<|&f64| -> f64> | ||
834 | 401..404 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> | ||
835 | 407..416 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>, Repeat<Map<|&f64| -> f64>>>(Repeat<Map<|&f64| -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> | ||
836 | 407..424 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> | ||
837 | 417..423 'repeat': Repeat<Map<|&f64| -> f64>> | ||
838 | 431..434 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> | ||
839 | 431..444 'vec.foo_bar()': {unknown} | ||
840 | "#]], | ||
841 | ); | ||
842 | } | ||
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs new file mode 100644 index 000000000..59eb59d5f --- /dev/null +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -0,0 +1,2218 @@ | |||
1 | use expect::expect; | ||
2 | |||
3 | use super::{check_infer, check_types}; | ||
4 | |||
5 | #[test] | ||
6 | fn infer_box() { | ||
7 | check_types( | ||
8 | r#" | ||
9 | //- /main.rs crate:main deps:std | ||
10 | fn test() { | ||
11 | let x = box 1; | ||
12 | let t = (x, box x, box &1, box [1]); | ||
13 | t; | ||
14 | } //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>) | ||
15 | |||
16 | //- /std.rs crate:std | ||
17 | #[prelude_import] use prelude::*; | ||
18 | mod prelude {} | ||
19 | |||
20 | mod boxed { | ||
21 | #[lang = "owned_box"] | ||
22 | pub struct Box<T: ?Sized> { | ||
23 | inner: *mut T, | ||
24 | } | ||
25 | } | ||
26 | "#, | ||
27 | ); | ||
28 | } | ||
29 | |||
30 | #[test] | ||
31 | fn infer_adt_self() { | ||
32 | check_types( | ||
33 | r#" | ||
34 | enum Nat { Succ(Self), Demo(Nat), Zero } | ||
35 | |||
36 | fn test() { | ||
37 | let foo: Nat = Nat::Zero; | ||
38 | if let Nat::Succ(x) = foo { | ||
39 | x | ||
40 | } //^ Nat | ||
41 | } | ||
42 | "#, | ||
43 | ); | ||
44 | } | ||
45 | |||
46 | #[test] | ||
47 | fn self_in_struct_lit() { | ||
48 | check_infer( | ||
49 | r#" | ||
50 | //- /main.rs | ||
51 | struct S<T> { x: T } | ||
52 | |||
53 | impl S<u32> { | ||
54 | fn foo() { | ||
55 | Self { x: 1 }; | ||
56 | } | ||
57 | } | ||
58 | "#, | ||
59 | expect![[r#" | ||
60 | 49..79 '{ ... }': () | ||
61 | 59..72 'Self { x: 1 }': S<u32> | ||
62 | 69..70 '1': u32 | ||
63 | "#]], | ||
64 | ); | ||
65 | } | ||
66 | |||
67 | #[test] | ||
68 | fn type_alias_in_struct_lit() { | ||
69 | check_infer( | ||
70 | r#" | ||
71 | //- /main.rs | ||
72 | struct S<T> { x: T } | ||
73 | |||
74 | type SS = S<u32>; | ||
75 | |||
76 | fn foo() { | ||
77 | SS { x: 1 }; | ||
78 | } | ||
79 | "#, | ||
80 | expect![[r#" | ||
81 | 50..70 '{ ...1 }; }': () | ||
82 | 56..67 'SS { x: 1 }': S<u32> | ||
83 | 64..65 '1': u32 | ||
84 | "#]], | ||
85 | ); | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn infer_ranges() { | ||
90 | check_types( | ||
91 | r#" | ||
92 | //- /main.rs crate:main deps:core | ||
93 | fn test() { | ||
94 | let a = ..; | ||
95 | let b = 1..; | ||
96 | let c = ..2u32; | ||
97 | let d = 1..2usize; | ||
98 | let e = ..=10; | ||
99 | let f = 'a'..='z'; | ||
100 | |||
101 | let t = (a, b, c, d, e, f); | ||
102 | t; | ||
103 | } //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>) | ||
104 | |||
105 | //- /core.rs crate:core | ||
106 | #[prelude_import] use prelude::*; | ||
107 | mod prelude {} | ||
108 | |||
109 | pub mod ops { | ||
110 | pub struct Range<Idx> { | ||
111 | pub start: Idx, | ||
112 | pub end: Idx, | ||
113 | } | ||
114 | pub struct RangeFrom<Idx> { | ||
115 | pub start: Idx, | ||
116 | } | ||
117 | struct RangeFull; | ||
118 | pub struct RangeInclusive<Idx> { | ||
119 | start: Idx, | ||
120 | end: Idx, | ||
121 | is_empty: u8, | ||
122 | } | ||
123 | pub struct RangeTo<Idx> { | ||
124 | pub end: Idx, | ||
125 | } | ||
126 | pub struct RangeToInclusive<Idx> { | ||
127 | pub end: Idx, | ||
128 | } | ||
129 | } | ||
130 | "#, | ||
131 | ); | ||
132 | } | ||
133 | |||
134 | #[test] | ||
135 | fn infer_while_let() { | ||
136 | check_types( | ||
137 | r#" | ||
138 | enum Option<T> { Some(T), None } | ||
139 | |||
140 | fn test() { | ||
141 | let foo: Option<f32> = None; | ||
142 | while let Option::Some(x) = foo { | ||
143 | x | ||
144 | } //^ f32 | ||
145 | } | ||
146 | "#, | ||
147 | ); | ||
148 | } | ||
149 | |||
150 | #[test] | ||
151 | fn infer_basics() { | ||
152 | check_infer( | ||
153 | r#" | ||
154 | fn test(a: u32, b: isize, c: !, d: &str) { | ||
155 | a; | ||
156 | b; | ||
157 | c; | ||
158 | d; | ||
159 | 1usize; | ||
160 | 1isize; | ||
161 | "test"; | ||
162 | 1.0f32; | ||
163 | }"#, | ||
164 | expect![[r#" | ||
165 | 8..9 'a': u32 | ||
166 | 16..17 'b': isize | ||
167 | 26..27 'c': ! | ||
168 | 32..33 'd': &str | ||
169 | 41..120 '{ ...f32; }': () | ||
170 | 47..48 'a': u32 | ||
171 | 54..55 'b': isize | ||
172 | 61..62 'c': ! | ||
173 | 68..69 'd': &str | ||
174 | 75..81 '1usize': usize | ||
175 | 87..93 '1isize': isize | ||
176 | 99..105 '"test"': &str | ||
177 | 111..117 '1.0f32': f32 | ||
178 | "#]], | ||
179 | ); | ||
180 | } | ||
181 | |||
182 | #[test] | ||
183 | fn infer_let() { | ||
184 | check_infer( | ||
185 | r#" | ||
186 | fn test() { | ||
187 | let a = 1isize; | ||
188 | let b: usize = 1; | ||
189 | let c = b; | ||
190 | let d: u32; | ||
191 | let e; | ||
192 | let f: i32 = e; | ||
193 | } | ||
194 | "#, | ||
195 | expect![[r#" | ||
196 | 10..117 '{ ...= e; }': () | ||
197 | 20..21 'a': isize | ||
198 | 24..30 '1isize': isize | ||
199 | 40..41 'b': usize | ||
200 | 51..52 '1': usize | ||
201 | 62..63 'c': usize | ||
202 | 66..67 'b': usize | ||
203 | 77..78 'd': u32 | ||
204 | 93..94 'e': i32 | ||
205 | 104..105 'f': i32 | ||
206 | 113..114 'e': i32 | ||
207 | "#]], | ||
208 | ); | ||
209 | } | ||
210 | |||
211 | #[test] | ||
212 | fn infer_paths() { | ||
213 | check_infer( | ||
214 | r#" | ||
215 | fn a() -> u32 { 1 } | ||
216 | |||
217 | mod b { | ||
218 | fn c() -> u32 { 1 } | ||
219 | } | ||
220 | |||
221 | fn test() { | ||
222 | a(); | ||
223 | b::c(); | ||
224 | } | ||
225 | "#, | ||
226 | expect![[r#" | ||
227 | 14..19 '{ 1 }': u32 | ||
228 | 16..17 '1': u32 | ||
229 | 47..52 '{ 1 }': u32 | ||
230 | 49..50 '1': u32 | ||
231 | 66..90 '{ ...c(); }': () | ||
232 | 72..73 'a': fn a() -> u32 | ||
233 | 72..75 'a()': u32 | ||
234 | 81..85 'b::c': fn c() -> u32 | ||
235 | 81..87 'b::c()': u32 | ||
236 | "#]], | ||
237 | ); | ||
238 | } | ||
239 | |||
240 | #[test] | ||
241 | fn infer_path_type() { | ||
242 | check_infer( | ||
243 | r#" | ||
244 | struct S; | ||
245 | |||
246 | impl S { | ||
247 | fn foo() -> i32 { 1 } | ||
248 | } | ||
249 | |||
250 | fn test() { | ||
251 | S::foo(); | ||
252 | <S>::foo(); | ||
253 | } | ||
254 | "#, | ||
255 | expect![[r#" | ||
256 | 40..45 '{ 1 }': i32 | ||
257 | 42..43 '1': i32 | ||
258 | 59..92 '{ ...o(); }': () | ||
259 | 65..71 'S::foo': fn foo() -> i32 | ||
260 | 65..73 'S::foo()': i32 | ||
261 | 79..87 '<S>::foo': fn foo() -> i32 | ||
262 | 79..89 '<S>::foo()': i32 | ||
263 | "#]], | ||
264 | ); | ||
265 | } | ||
266 | |||
267 | #[test] | ||
268 | fn infer_struct() { | ||
269 | check_infer( | ||
270 | r#" | ||
271 | struct A { | ||
272 | b: B, | ||
273 | c: C, | ||
274 | } | ||
275 | struct B; | ||
276 | struct C(usize); | ||
277 | |||
278 | fn test() { | ||
279 | let c = C(1); | ||
280 | B; | ||
281 | let a: A = A { b: B, c: C(1) }; | ||
282 | a.b; | ||
283 | a.c; | ||
284 | } | ||
285 | "#, | ||
286 | expect![[r#" | ||
287 | 71..153 '{ ...a.c; }': () | ||
288 | 81..82 'c': C | ||
289 | 85..86 'C': C(usize) -> C | ||
290 | 85..89 'C(1)': C | ||
291 | 87..88 '1': usize | ||
292 | 95..96 'B': B | ||
293 | 106..107 'a': A | ||
294 | 113..132 'A { b:...C(1) }': A | ||
295 | 120..121 'B': B | ||
296 | 126..127 'C': C(usize) -> C | ||
297 | 126..130 'C(1)': C | ||
298 | 128..129 '1': usize | ||
299 | 138..139 'a': A | ||
300 | 138..141 'a.b': B | ||
301 | 147..148 'a': A | ||
302 | 147..150 'a.c': C | ||
303 | "#]], | ||
304 | ); | ||
305 | } | ||
306 | |||
307 | #[test] | ||
308 | fn infer_enum() { | ||
309 | check_infer( | ||
310 | r#" | ||
311 | enum E { | ||
312 | V1 { field: u32 }, | ||
313 | V2 | ||
314 | } | ||
315 | fn test() { | ||
316 | E::V1 { field: 1 }; | ||
317 | E::V2; | ||
318 | }"#, | ||
319 | expect![[r#" | ||
320 | 51..89 '{ ...:V2; }': () | ||
321 | 57..75 'E::V1 ...d: 1 }': E | ||
322 | 72..73 '1': u32 | ||
323 | 81..86 'E::V2': E | ||
324 | "#]], | ||
325 | ); | ||
326 | } | ||
327 | |||
328 | #[test] | ||
329 | fn infer_union() { | ||
330 | check_infer( | ||
331 | r#" | ||
332 | union MyUnion { | ||
333 | foo: u32, | ||
334 | bar: f32, | ||
335 | } | ||
336 | |||
337 | fn test() { | ||
338 | let u = MyUnion { foo: 0 }; | ||
339 | unsafe { baz(u); } | ||
340 | let u = MyUnion { bar: 0.0 }; | ||
341 | unsafe { baz(u); } | ||
342 | } | ||
343 | |||
344 | unsafe fn baz(u: MyUnion) { | ||
345 | let inner = u.foo; | ||
346 | let inner = u.bar; | ||
347 | } | ||
348 | "#, | ||
349 | expect![[r#" | ||
350 | 57..172 '{ ...); } }': () | ||
351 | 67..68 'u': MyUnion | ||
352 | 71..89 'MyUnio...o: 0 }': MyUnion | ||
353 | 86..87 '0': u32 | ||
354 | 95..113 'unsafe...(u); }': () | ||
355 | 102..113 '{ baz(u); }': () | ||
356 | 104..107 'baz': fn baz(MyUnion) | ||
357 | 104..110 'baz(u)': () | ||
358 | 108..109 'u': MyUnion | ||
359 | 122..123 'u': MyUnion | ||
360 | 126..146 'MyUnio... 0.0 }': MyUnion | ||
361 | 141..144 '0.0': f32 | ||
362 | 152..170 'unsafe...(u); }': () | ||
363 | 159..170 '{ baz(u); }': () | ||
364 | 161..164 'baz': fn baz(MyUnion) | ||
365 | 161..167 'baz(u)': () | ||
366 | 165..166 'u': MyUnion | ||
367 | 188..189 'u': MyUnion | ||
368 | 200..249 '{ ...bar; }': () | ||
369 | 210..215 'inner': u32 | ||
370 | 218..219 'u': MyUnion | ||
371 | 218..223 'u.foo': u32 | ||
372 | 233..238 'inner': f32 | ||
373 | 241..242 'u': MyUnion | ||
374 | 241..246 'u.bar': f32 | ||
375 | "#]], | ||
376 | ); | ||
377 | } | ||
378 | |||
379 | #[test] | ||
380 | fn infer_refs() { | ||
381 | check_infer( | ||
382 | r#" | ||
383 | fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { | ||
384 | a; | ||
385 | *a; | ||
386 | &a; | ||
387 | &mut a; | ||
388 | b; | ||
389 | *b; | ||
390 | &b; | ||
391 | c; | ||
392 | *c; | ||
393 | d; | ||
394 | *d; | ||
395 | } | ||
396 | "#, | ||
397 | expect![[r#" | ||
398 | 8..9 'a': &u32 | ||
399 | 17..18 'b': &mut u32 | ||
400 | 30..31 'c': *const u32 | ||
401 | 45..46 'd': *mut u32 | ||
402 | 58..149 '{ ... *d; }': () | ||
403 | 64..65 'a': &u32 | ||
404 | 71..73 '*a': u32 | ||
405 | 72..73 'a': &u32 | ||
406 | 79..81 '&a': &&u32 | ||
407 | 80..81 'a': &u32 | ||
408 | 87..93 '&mut a': &mut &u32 | ||
409 | 92..93 'a': &u32 | ||
410 | 99..100 'b': &mut u32 | ||
411 | 106..108 '*b': u32 | ||
412 | 107..108 'b': &mut u32 | ||
413 | 114..116 '&b': &&mut u32 | ||
414 | 115..116 'b': &mut u32 | ||
415 | 122..123 'c': *const u32 | ||
416 | 129..131 '*c': u32 | ||
417 | 130..131 'c': *const u32 | ||
418 | 137..138 'd': *mut u32 | ||
419 | 144..146 '*d': u32 | ||
420 | 145..146 'd': *mut u32 | ||
421 | "#]], | ||
422 | ); | ||
423 | } | ||
424 | |||
425 | #[test] | ||
426 | fn infer_raw_ref() { | ||
427 | check_infer( | ||
428 | r#" | ||
429 | fn test(a: i32) { | ||
430 | &raw mut a; | ||
431 | &raw const a; | ||
432 | } | ||
433 | "#, | ||
434 | expect![[r#" | ||
435 | 8..9 'a': i32 | ||
436 | 16..53 '{ ...t a; }': () | ||
437 | 22..32 '&raw mut a': *mut i32 | ||
438 | 31..32 'a': i32 | ||
439 | 38..50 '&raw const a': *const i32 | ||
440 | 49..50 'a': i32 | ||
441 | "#]], | ||
442 | ); | ||
443 | } | ||
444 | |||
445 | #[test] | ||
446 | fn infer_literals() { | ||
447 | check_infer( | ||
448 | r##" | ||
449 | fn test() { | ||
450 | 5i32; | ||
451 | 5f32; | ||
452 | 5f64; | ||
453 | "hello"; | ||
454 | b"bytes"; | ||
455 | 'c'; | ||
456 | b'b'; | ||
457 | 3.14; | ||
458 | 5000; | ||
459 | false; | ||
460 | true; | ||
461 | r#" | ||
462 | //! doc | ||
463 | // non-doc | ||
464 | mod foo {} | ||
465 | "#; | ||
466 | br#"yolo"#; | ||
467 | } | ||
468 | "##, | ||
469 | expect![[r##" | ||
470 | 10..216 '{ ...o"#; }': () | ||
471 | 16..20 '5i32': i32 | ||
472 | 26..30 '5f32': f32 | ||
473 | 36..40 '5f64': f64 | ||
474 | 46..53 '"hello"': &str | ||
475 | 59..67 'b"bytes"': &[u8; _] | ||
476 | 73..76 ''c'': char | ||
477 | 82..86 'b'b'': u8 | ||
478 | 92..96 '3.14': f64 | ||
479 | 102..106 '5000': i32 | ||
480 | 112..117 'false': bool | ||
481 | 123..127 'true': bool | ||
482 | 133..197 'r#" ... "#': &str | ||
483 | 203..213 'br#"yolo"#': &[u8; _] | ||
484 | "##]], | ||
485 | ); | ||
486 | } | ||
487 | |||
488 | #[test] | ||
489 | fn infer_unary_op() { | ||
490 | check_infer( | ||
491 | r#" | ||
492 | enum SomeType {} | ||
493 | |||
494 | fn test(x: SomeType) { | ||
495 | let b = false; | ||
496 | let c = !b; | ||
497 | let a = 100; | ||
498 | let d: i128 = -a; | ||
499 | let e = -100; | ||
500 | let f = !!!true; | ||
501 | let g = !42; | ||
502 | let h = !10u32; | ||
503 | let j = !a; | ||
504 | -3.14; | ||
505 | !3; | ||
506 | -x; | ||
507 | !x; | ||
508 | -"hello"; | ||
509 | !"hello"; | ||
510 | } | ||
511 | "#, | ||
512 | expect![[r#" | ||
513 | 26..27 'x': SomeType | ||
514 | 39..271 '{ ...lo"; }': () | ||
515 | 49..50 'b': bool | ||
516 | 53..58 'false': bool | ||
517 | 68..69 'c': bool | ||
518 | 72..74 '!b': bool | ||
519 | 73..74 'b': bool | ||
520 | 84..85 'a': i128 | ||
521 | 88..91 '100': i128 | ||
522 | 101..102 'd': i128 | ||
523 | 111..113 '-a': i128 | ||
524 | 112..113 'a': i128 | ||
525 | 123..124 'e': i32 | ||
526 | 127..131 '-100': i32 | ||
527 | 128..131 '100': i32 | ||
528 | 141..142 'f': bool | ||
529 | 145..152 '!!!true': bool | ||
530 | 146..152 '!!true': bool | ||
531 | 147..152 '!true': bool | ||
532 | 148..152 'true': bool | ||
533 | 162..163 'g': i32 | ||
534 | 166..169 '!42': i32 | ||
535 | 167..169 '42': i32 | ||
536 | 179..180 'h': u32 | ||
537 | 183..189 '!10u32': u32 | ||
538 | 184..189 '10u32': u32 | ||
539 | 199..200 'j': i128 | ||
540 | 203..205 '!a': i128 | ||
541 | 204..205 'a': i128 | ||
542 | 211..216 '-3.14': f64 | ||
543 | 212..216 '3.14': f64 | ||
544 | 222..224 '!3': i32 | ||
545 | 223..224 '3': i32 | ||
546 | 230..232 '-x': {unknown} | ||
547 | 231..232 'x': SomeType | ||
548 | 238..240 '!x': {unknown} | ||
549 | 239..240 'x': SomeType | ||
550 | 246..254 '-"hello"': {unknown} | ||
551 | 247..254 '"hello"': &str | ||
552 | 260..268 '!"hello"': {unknown} | ||
553 | 261..268 '"hello"': &str | ||
554 | "#]], | ||
555 | ); | ||
556 | } | ||
557 | |||
558 | #[test] | ||
559 | fn infer_backwards() { | ||
560 | check_infer( | ||
561 | r#" | ||
562 | fn takes_u32(x: u32) {} | ||
563 | |||
564 | struct S { i32_field: i32 } | ||
565 | |||
566 | fn test() -> &mut &f64 { | ||
567 | let a = unknown_function(); | ||
568 | takes_u32(a); | ||
569 | let b = unknown_function(); | ||
570 | S { i32_field: b }; | ||
571 | let c = unknown_function(); | ||
572 | &mut &c | ||
573 | } | ||
574 | "#, | ||
575 | expect![[r#" | ||
576 | 13..14 'x': u32 | ||
577 | 21..23 '{}': () | ||
578 | 77..230 '{ ...t &c }': &mut &f64 | ||
579 | 87..88 'a': u32 | ||
580 | 91..107 'unknow...nction': {unknown} | ||
581 | 91..109 'unknow...tion()': u32 | ||
582 | 115..124 'takes_u32': fn takes_u32(u32) | ||
583 | 115..127 'takes_u32(a)': () | ||
584 | 125..126 'a': u32 | ||
585 | 137..138 'b': i32 | ||
586 | 141..157 'unknow...nction': {unknown} | ||
587 | 141..159 'unknow...tion()': i32 | ||
588 | 165..183 'S { i3...d: b }': S | ||
589 | 180..181 'b': i32 | ||
590 | 193..194 'c': f64 | ||
591 | 197..213 'unknow...nction': {unknown} | ||
592 | 197..215 'unknow...tion()': f64 | ||
593 | 221..228 '&mut &c': &mut &f64 | ||
594 | 226..228 '&c': &f64 | ||
595 | 227..228 'c': f64 | ||
596 | "#]], | ||
597 | ); | ||
598 | } | ||
599 | |||
600 | #[test] | ||
601 | fn infer_self() { | ||
602 | check_infer( | ||
603 | r#" | ||
604 | struct S; | ||
605 | |||
606 | impl S { | ||
607 | fn test(&self) { | ||
608 | self; | ||
609 | } | ||
610 | fn test2(self: &Self) { | ||
611 | self; | ||
612 | } | ||
613 | fn test3() -> Self { | ||
614 | S {} | ||
615 | } | ||
616 | fn test4() -> Self { | ||
617 | Self {} | ||
618 | } | ||
619 | } | ||
620 | "#, | ||
621 | expect![[r#" | ||
622 | 33..37 'self': &S | ||
623 | 39..60 '{ ... }': () | ||
624 | 49..53 'self': &S | ||
625 | 74..78 'self': &S | ||
626 | 87..108 '{ ... }': () | ||
627 | 97..101 'self': &S | ||
628 | 132..152 '{ ... }': S | ||
629 | 142..146 'S {}': S | ||
630 | 176..199 '{ ... }': S | ||
631 | 186..193 'Self {}': S | ||
632 | "#]], | ||
633 | ); | ||
634 | } | ||
635 | |||
636 | #[test] | ||
637 | fn infer_self_as_path() { | ||
638 | check_infer( | ||
639 | r#" | ||
640 | struct S1; | ||
641 | struct S2(isize); | ||
642 | enum E { | ||
643 | V1, | ||
644 | V2(u32), | ||
645 | } | ||
646 | |||
647 | impl S1 { | ||
648 | fn test() { | ||
649 | Self; | ||
650 | } | ||
651 | } | ||
652 | impl S2 { | ||
653 | fn test() { | ||
654 | Self(1); | ||
655 | } | ||
656 | } | ||
657 | impl E { | ||
658 | fn test() { | ||
659 | Self::V1; | ||
660 | Self::V2(1); | ||
661 | } | ||
662 | } | ||
663 | "#, | ||
664 | expect![[r#" | ||
665 | 86..107 '{ ... }': () | ||
666 | 96..100 'Self': S1 | ||
667 | 134..158 '{ ... }': () | ||
668 | 144..148 'Self': S2(isize) -> S2 | ||
669 | 144..151 'Self(1)': S2 | ||
670 | 149..150 '1': isize | ||
671 | 184..230 '{ ... }': () | ||
672 | 194..202 'Self::V1': E | ||
673 | 212..220 'Self::V2': V2(u32) -> E | ||
674 | 212..223 'Self::V2(1)': E | ||
675 | 221..222 '1': u32 | ||
676 | "#]], | ||
677 | ); | ||
678 | } | ||
679 | |||
680 | #[test] | ||
681 | fn infer_binary_op() { | ||
682 | check_infer( | ||
683 | r#" | ||
684 | fn f(x: bool) -> i32 { | ||
685 | 0i32 | ||
686 | } | ||
687 | |||
688 | fn test() -> bool { | ||
689 | let x = a && b; | ||
690 | let y = true || false; | ||
691 | let z = x == y; | ||
692 | let t = x != y; | ||
693 | let minus_forty: isize = -40isize; | ||
694 | let h = minus_forty <= CONST_2; | ||
695 | let c = f(z || y) + 5; | ||
696 | let d = b; | ||
697 | let g = minus_forty ^= i; | ||
698 | let ten: usize = 10; | ||
699 | let ten_is_eleven = ten == some_num; | ||
700 | |||
701 | ten < 3 | ||
702 | } | ||
703 | "#, | ||
704 | expect![[r#" | ||
705 | 5..6 'x': bool | ||
706 | 21..33 '{ 0i32 }': i32 | ||
707 | 27..31 '0i32': i32 | ||
708 | 53..369 '{ ... < 3 }': bool | ||
709 | 63..64 'x': bool | ||
710 | 67..68 'a': bool | ||
711 | 67..73 'a && b': bool | ||
712 | 72..73 'b': bool | ||
713 | 83..84 'y': bool | ||
714 | 87..91 'true': bool | ||
715 | 87..100 'true || false': bool | ||
716 | 95..100 'false': bool | ||
717 | 110..111 'z': bool | ||
718 | 114..115 'x': bool | ||
719 | 114..120 'x == y': bool | ||
720 | 119..120 'y': bool | ||
721 | 130..131 't': bool | ||
722 | 134..135 'x': bool | ||
723 | 134..140 'x != y': bool | ||
724 | 139..140 'y': bool | ||
725 | 150..161 'minus_forty': isize | ||
726 | 171..179 '-40isize': isize | ||
727 | 172..179 '40isize': isize | ||
728 | 189..190 'h': bool | ||
729 | 193..204 'minus_forty': isize | ||
730 | 193..215 'minus_...ONST_2': bool | ||
731 | 208..215 'CONST_2': isize | ||
732 | 225..226 'c': i32 | ||
733 | 229..230 'f': fn f(bool) -> i32 | ||
734 | 229..238 'f(z || y)': i32 | ||
735 | 229..242 'f(z || y) + 5': i32 | ||
736 | 231..232 'z': bool | ||
737 | 231..237 'z || y': bool | ||
738 | 236..237 'y': bool | ||
739 | 241..242 '5': i32 | ||
740 | 252..253 'd': {unknown} | ||
741 | 256..257 'b': {unknown} | ||
742 | 267..268 'g': () | ||
743 | 271..282 'minus_forty': isize | ||
744 | 271..287 'minus_...y ^= i': () | ||
745 | 286..287 'i': isize | ||
746 | 297..300 'ten': usize | ||
747 | 310..312 '10': usize | ||
748 | 322..335 'ten_is_eleven': bool | ||
749 | 338..341 'ten': usize | ||
750 | 338..353 'ten == some_num': bool | ||
751 | 345..353 'some_num': usize | ||
752 | 360..363 'ten': usize | ||
753 | 360..367 'ten < 3': bool | ||
754 | 366..367 '3': usize | ||
755 | "#]], | ||
756 | ); | ||
757 | } | ||
758 | |||
759 | #[test] | ||
760 | fn infer_shift_op() { | ||
761 | check_infer( | ||
762 | r#" | ||
763 | fn test() { | ||
764 | 1u32 << 5u8; | ||
765 | 1u32 >> 5u8; | ||
766 | } | ||
767 | "#, | ||
768 | expect![[r#" | ||
769 | 10..47 '{ ...5u8; }': () | ||
770 | 16..20 '1u32': u32 | ||
771 | 16..27 '1u32 << 5u8': u32 | ||
772 | 24..27 '5u8': u8 | ||
773 | 33..37 '1u32': u32 | ||
774 | 33..44 '1u32 >> 5u8': u32 | ||
775 | 41..44 '5u8': u8 | ||
776 | "#]], | ||
777 | ); | ||
778 | } | ||
779 | |||
780 | #[test] | ||
781 | fn infer_field_autoderef() { | ||
782 | check_infer( | ||
783 | r#" | ||
784 | struct A { | ||
785 | b: B, | ||
786 | } | ||
787 | struct B; | ||
788 | |||
789 | fn test1(a: A) { | ||
790 | let a1 = a; | ||
791 | a1.b; | ||
792 | let a2 = &a; | ||
793 | a2.b; | ||
794 | let a3 = &mut a; | ||
795 | a3.b; | ||
796 | let a4 = &&&&&&&a; | ||
797 | a4.b; | ||
798 | let a5 = &mut &&mut &&mut a; | ||
799 | a5.b; | ||
800 | } | ||
801 | |||
802 | fn test2(a1: *const A, a2: *mut A) { | ||
803 | a1.b; | ||
804 | a2.b; | ||
805 | } | ||
806 | "#, | ||
807 | expect![[r#" | ||
808 | 43..44 'a': A | ||
809 | 49..212 '{ ...5.b; }': () | ||
810 | 59..61 'a1': A | ||
811 | 64..65 'a': A | ||
812 | 71..73 'a1': A | ||
813 | 71..75 'a1.b': B | ||
814 | 85..87 'a2': &A | ||
815 | 90..92 '&a': &A | ||
816 | 91..92 'a': A | ||
817 | 98..100 'a2': &A | ||
818 | 98..102 'a2.b': B | ||
819 | 112..114 'a3': &mut A | ||
820 | 117..123 '&mut a': &mut A | ||
821 | 122..123 'a': A | ||
822 | 129..131 'a3': &mut A | ||
823 | 129..133 'a3.b': B | ||
824 | 143..145 'a4': &&&&&&&A | ||
825 | 148..156 '&&&&&&&a': &&&&&&&A | ||
826 | 149..156 '&&&&&&a': &&&&&&A | ||
827 | 150..156 '&&&&&a': &&&&&A | ||
828 | 151..156 '&&&&a': &&&&A | ||
829 | 152..156 '&&&a': &&&A | ||
830 | 153..156 '&&a': &&A | ||
831 | 154..156 '&a': &A | ||
832 | 155..156 'a': A | ||
833 | 162..164 'a4': &&&&&&&A | ||
834 | 162..166 'a4.b': B | ||
835 | 176..178 'a5': &mut &&mut &&mut A | ||
836 | 181..199 '&mut &...&mut a': &mut &&mut &&mut A | ||
837 | 186..199 '&&mut &&mut a': &&mut &&mut A | ||
838 | 187..199 '&mut &&mut a': &mut &&mut A | ||
839 | 192..199 '&&mut a': &&mut A | ||
840 | 193..199 '&mut a': &mut A | ||
841 | 198..199 'a': A | ||
842 | 205..207 'a5': &mut &&mut &&mut A | ||
843 | 205..209 'a5.b': B | ||
844 | 223..225 'a1': *const A | ||
845 | 237..239 'a2': *mut A | ||
846 | 249..272 '{ ...2.b; }': () | ||
847 | 255..257 'a1': *const A | ||
848 | 255..259 'a1.b': B | ||
849 | 265..267 'a2': *mut A | ||
850 | 265..269 'a2.b': B | ||
851 | "#]], | ||
852 | ); | ||
853 | } | ||
854 | |||
855 | #[test] | ||
856 | fn infer_argument_autoderef() { | ||
857 | check_infer( | ||
858 | r#" | ||
859 | #[lang = "deref"] | ||
860 | pub trait Deref { | ||
861 | type Target; | ||
862 | fn deref(&self) -> &Self::Target; | ||
863 | } | ||
864 | |||
865 | struct A<T>(T); | ||
866 | |||
867 | impl<T> A<T> { | ||
868 | fn foo(&self) -> &T { | ||
869 | &self.0 | ||
870 | } | ||
871 | } | ||
872 | |||
873 | struct B<T>(T); | ||
874 | |||
875 | impl<T> Deref for B<T> { | ||
876 | type Target = T; | ||
877 | fn deref(&self) -> &Self::Target { | ||
878 | &self.0 | ||
879 | } | ||
880 | } | ||
881 | |||
882 | fn test() { | ||
883 | let t = A::foo(&&B(B(A(42)))); | ||
884 | } | ||
885 | "#, | ||
886 | expect![[r#" | ||
887 | 67..71 'self': &Self | ||
888 | 138..142 'self': &A<T> | ||
889 | 150..173 '{ ... }': &T | ||
890 | 160..167 '&self.0': &T | ||
891 | 161..165 'self': &A<T> | ||
892 | 161..167 'self.0': T | ||
893 | 254..258 'self': &B<T> | ||
894 | 277..300 '{ ... }': &T | ||
895 | 287..294 '&self.0': &T | ||
896 | 288..292 'self': &B<T> | ||
897 | 288..294 'self.0': T | ||
898 | 314..352 '{ ...))); }': () | ||
899 | 324..325 't': &i32 | ||
900 | 328..334 'A::foo': fn foo<i32>(&A<i32>) -> &i32 | ||
901 | 328..349 'A::foo...42))))': &i32 | ||
902 | 335..348 '&&B(B(A(42)))': &&B<B<A<i32>>> | ||
903 | 336..348 '&B(B(A(42)))': &B<B<A<i32>>> | ||
904 | 337..338 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> | ||
905 | 337..348 'B(B(A(42)))': B<B<A<i32>>> | ||
906 | 339..340 'B': B<A<i32>>(A<i32>) -> B<A<i32>> | ||
907 | 339..347 'B(A(42))': B<A<i32>> | ||
908 | 341..342 'A': A<i32>(i32) -> A<i32> | ||
909 | 341..346 'A(42)': A<i32> | ||
910 | 343..345 '42': i32 | ||
911 | "#]], | ||
912 | ); | ||
913 | } | ||
914 | |||
915 | #[test] | ||
916 | fn infer_method_argument_autoderef() { | ||
917 | check_infer( | ||
918 | r#" | ||
919 | #[lang = "deref"] | ||
920 | pub trait Deref { | ||
921 | type Target; | ||
922 | fn deref(&self) -> &Self::Target; | ||
923 | } | ||
924 | |||
925 | struct A<T>(*mut T); | ||
926 | |||
927 | impl<T> A<T> { | ||
928 | fn foo(&self, x: &A<T>) -> &T { | ||
929 | &*x.0 | ||
930 | } | ||
931 | } | ||
932 | |||
933 | struct B<T>(T); | ||
934 | |||
935 | impl<T> Deref for B<T> { | ||
936 | type Target = T; | ||
937 | fn deref(&self) -> &Self::Target { | ||
938 | &self.0 | ||
939 | } | ||
940 | } | ||
941 | |||
942 | fn test(a: A<i32>) { | ||
943 | let t = A(0 as *mut _).foo(&&B(B(a))); | ||
944 | } | ||
945 | "#, | ||
946 | expect![[r#" | ||
947 | 67..71 'self': &Self | ||
948 | 143..147 'self': &A<T> | ||
949 | 149..150 'x': &A<T> | ||
950 | 165..186 '{ ... }': &T | ||
951 | 175..180 '&*x.0': &T | ||
952 | 176..180 '*x.0': T | ||
953 | 177..178 'x': &A<T> | ||
954 | 177..180 'x.0': *mut T | ||
955 | 267..271 'self': &B<T> | ||
956 | 290..313 '{ ... }': &T | ||
957 | 300..307 '&self.0': &T | ||
958 | 301..305 'self': &B<T> | ||
959 | 301..307 'self.0': T | ||
960 | 325..326 'a': A<i32> | ||
961 | 336..382 '{ ...))); }': () | ||
962 | 346..347 't': &i32 | ||
963 | 350..351 'A': A<i32>(*mut i32) -> A<i32> | ||
964 | 350..364 'A(0 as *mut _)': A<i32> | ||
965 | 350..379 'A(0 as...B(a)))': &i32 | ||
966 | 352..353 '0': i32 | ||
967 | 352..363 '0 as *mut _': *mut i32 | ||
968 | 369..378 '&&B(B(a))': &&B<B<A<i32>>> | ||
969 | 370..378 '&B(B(a))': &B<B<A<i32>>> | ||
970 | 371..372 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> | ||
971 | 371..378 'B(B(a))': B<B<A<i32>>> | ||
972 | 373..374 'B': B<A<i32>>(A<i32>) -> B<A<i32>> | ||
973 | 373..377 'B(a)': B<A<i32>> | ||
974 | 375..376 'a': A<i32> | ||
975 | "#]], | ||
976 | ); | ||
977 | } | ||
978 | |||
979 | #[test] | ||
980 | fn infer_in_elseif() { | ||
981 | check_infer( | ||
982 | r#" | ||
983 | struct Foo { field: i32 } | ||
984 | fn main(foo: Foo) { | ||
985 | if true { | ||
986 | |||
987 | } else if false { | ||
988 | foo.field | ||
989 | } | ||
990 | } | ||
991 | "#, | ||
992 | expect![[r#" | ||
993 | 34..37 'foo': Foo | ||
994 | 44..108 '{ ... } }': () | ||
995 | 50..106 'if tru... }': () | ||
996 | 53..57 'true': bool | ||
997 | 58..66 '{ }': () | ||
998 | 72..106 'if fal... }': i32 | ||
999 | 75..80 'false': bool | ||
1000 | 81..106 '{ ... }': i32 | ||
1001 | 91..94 'foo': Foo | ||
1002 | 91..100 'foo.field': i32 | ||
1003 | "#]], | ||
1004 | ) | ||
1005 | } | ||
1006 | |||
1007 | #[test] | ||
1008 | fn infer_if_match_with_return() { | ||
1009 | check_infer( | ||
1010 | r#" | ||
1011 | fn foo() { | ||
1012 | let _x1 = if true { | ||
1013 | 1 | ||
1014 | } else { | ||
1015 | return; | ||
1016 | }; | ||
1017 | let _x2 = if true { | ||
1018 | 2 | ||
1019 | } else { | ||
1020 | return | ||
1021 | }; | ||
1022 | let _x3 = match true { | ||
1023 | true => 3, | ||
1024 | _ => { | ||
1025 | return; | ||
1026 | } | ||
1027 | }; | ||
1028 | let _x4 = match true { | ||
1029 | true => 4, | ||
1030 | _ => return | ||
1031 | }; | ||
1032 | }"#, | ||
1033 | expect![[r#" | ||
1034 | 9..322 '{ ... }; }': () | ||
1035 | 19..22 '_x1': i32 | ||
1036 | 25..79 'if tru... }': i32 | ||
1037 | 28..32 'true': bool | ||
1038 | 33..50 '{ ... }': i32 | ||
1039 | 43..44 '1': i32 | ||
1040 | 56..79 '{ ... }': i32 | ||
1041 | 66..72 'return': ! | ||
1042 | 89..92 '_x2': i32 | ||
1043 | 95..148 'if tru... }': i32 | ||
1044 | 98..102 'true': bool | ||
1045 | 103..120 '{ ... }': i32 | ||
1046 | 113..114 '2': i32 | ||
1047 | 126..148 '{ ... }': ! | ||
1048 | 136..142 'return': ! | ||
1049 | 158..161 '_x3': i32 | ||
1050 | 164..246 'match ... }': i32 | ||
1051 | 170..174 'true': bool | ||
1052 | 185..189 'true': bool | ||
1053 | 185..189 'true': bool | ||
1054 | 193..194 '3': i32 | ||
1055 | 204..205 '_': bool | ||
1056 | 209..240 '{ ... }': i32 | ||
1057 | 223..229 'return': ! | ||
1058 | 256..259 '_x4': i32 | ||
1059 | 262..319 'match ... }': i32 | ||
1060 | 268..272 'true': bool | ||
1061 | 283..287 'true': bool | ||
1062 | 283..287 'true': bool | ||
1063 | 291..292 '4': i32 | ||
1064 | 302..303 '_': bool | ||
1065 | 307..313 'return': ! | ||
1066 | "#]], | ||
1067 | ) | ||
1068 | } | ||
1069 | |||
1070 | #[test] | ||
1071 | fn infer_inherent_method() { | ||
1072 | check_infer( | ||
1073 | r#" | ||
1074 | struct A; | ||
1075 | |||
1076 | impl A { | ||
1077 | fn foo(self, x: u32) -> i32 {} | ||
1078 | } | ||
1079 | |||
1080 | mod b { | ||
1081 | impl super::A { | ||
1082 | fn bar(&self, x: u64) -> i64 {} | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1086 | fn test(a: A) { | ||
1087 | a.foo(1); | ||
1088 | (&a).bar(1); | ||
1089 | a.bar(1); | ||
1090 | } | ||
1091 | "#, | ||
1092 | expect![[r#" | ||
1093 | 31..35 'self': A | ||
1094 | 37..38 'x': u32 | ||
1095 | 52..54 '{}': () | ||
1096 | 102..106 'self': &A | ||
1097 | 108..109 'x': u64 | ||
1098 | 123..125 '{}': () | ||
1099 | 143..144 'a': A | ||
1100 | 149..197 '{ ...(1); }': () | ||
1101 | 155..156 'a': A | ||
1102 | 155..163 'a.foo(1)': i32 | ||
1103 | 161..162 '1': u32 | ||
1104 | 169..180 '(&a).bar(1)': i64 | ||
1105 | 170..172 '&a': &A | ||
1106 | 171..172 'a': A | ||
1107 | 178..179 '1': u64 | ||
1108 | 186..187 'a': A | ||
1109 | 186..194 'a.bar(1)': i64 | ||
1110 | 192..193 '1': u64 | ||
1111 | "#]], | ||
1112 | ); | ||
1113 | } | ||
1114 | |||
1115 | #[test] | ||
1116 | fn infer_inherent_method_str() { | ||
1117 | check_infer( | ||
1118 | r#" | ||
1119 | #[lang = "str"] | ||
1120 | impl str { | ||
1121 | fn foo(&self) -> i32 {} | ||
1122 | } | ||
1123 | |||
1124 | fn test() { | ||
1125 | "foo".foo(); | ||
1126 | } | ||
1127 | "#, | ||
1128 | expect![[r#" | ||
1129 | 39..43 'self': &str | ||
1130 | 52..54 '{}': () | ||
1131 | 68..88 '{ ...o(); }': () | ||
1132 | 74..79 '"foo"': &str | ||
1133 | 74..85 '"foo".foo()': i32 | ||
1134 | "#]], | ||
1135 | ); | ||
1136 | } | ||
1137 | |||
1138 | #[test] | ||
1139 | fn infer_tuple() { | ||
1140 | check_infer( | ||
1141 | r#" | ||
1142 | fn test(x: &str, y: isize) { | ||
1143 | let a: (u32, &str) = (1, "a"); | ||
1144 | let b = (a, x); | ||
1145 | let c = (y, x); | ||
1146 | let d = (c, x); | ||
1147 | let e = (1, "e"); | ||
1148 | let f = (e, "d"); | ||
1149 | } | ||
1150 | "#, | ||
1151 | expect![[r#" | ||
1152 | 8..9 'x': &str | ||
1153 | 17..18 'y': isize | ||
1154 | 27..169 '{ ...d"); }': () | ||
1155 | 37..38 'a': (u32, &str) | ||
1156 | 54..62 '(1, "a")': (u32, &str) | ||
1157 | 55..56 '1': u32 | ||
1158 | 58..61 '"a"': &str | ||
1159 | 72..73 'b': ((u32, &str), &str) | ||
1160 | 76..82 '(a, x)': ((u32, &str), &str) | ||
1161 | 77..78 'a': (u32, &str) | ||
1162 | 80..81 'x': &str | ||
1163 | 92..93 'c': (isize, &str) | ||
1164 | 96..102 '(y, x)': (isize, &str) | ||
1165 | 97..98 'y': isize | ||
1166 | 100..101 'x': &str | ||
1167 | 112..113 'd': ((isize, &str), &str) | ||
1168 | 116..122 '(c, x)': ((isize, &str), &str) | ||
1169 | 117..118 'c': (isize, &str) | ||
1170 | 120..121 'x': &str | ||
1171 | 132..133 'e': (i32, &str) | ||
1172 | 136..144 '(1, "e")': (i32, &str) | ||
1173 | 137..138 '1': i32 | ||
1174 | 140..143 '"e"': &str | ||
1175 | 154..155 'f': ((i32, &str), &str) | ||
1176 | 158..166 '(e, "d")': ((i32, &str), &str) | ||
1177 | 159..160 'e': (i32, &str) | ||
1178 | 162..165 '"d"': &str | ||
1179 | "#]], | ||
1180 | ); | ||
1181 | } | ||
1182 | |||
1183 | #[test] | ||
1184 | fn infer_array() { | ||
1185 | check_infer( | ||
1186 | r#" | ||
1187 | fn test(x: &str, y: isize) { | ||
1188 | let a = [x]; | ||
1189 | let b = [a, a]; | ||
1190 | let c = [b, b]; | ||
1191 | |||
1192 | let d = [y, 1, 2, 3]; | ||
1193 | let d = [1, y, 2, 3]; | ||
1194 | let e = [y]; | ||
1195 | let f = [d, d]; | ||
1196 | let g = [e, e]; | ||
1197 | |||
1198 | let h = [1, 2]; | ||
1199 | let i = ["a", "b"]; | ||
1200 | |||
1201 | let b = [a, ["b"]]; | ||
1202 | let x: [u8; 0] = []; | ||
1203 | } | ||
1204 | "#, | ||
1205 | expect![[r#" | ||
1206 | 8..9 'x': &str | ||
1207 | 17..18 'y': isize | ||
1208 | 27..292 '{ ... []; }': () | ||
1209 | 37..38 'a': [&str; _] | ||
1210 | 41..44 '[x]': [&str; _] | ||
1211 | 42..43 'x': &str | ||
1212 | 54..55 'b': [[&str; _]; _] | ||
1213 | 58..64 '[a, a]': [[&str; _]; _] | ||
1214 | 59..60 'a': [&str; _] | ||
1215 | 62..63 'a': [&str; _] | ||
1216 | 74..75 'c': [[[&str; _]; _]; _] | ||
1217 | 78..84 '[b, b]': [[[&str; _]; _]; _] | ||
1218 | 79..80 'b': [[&str; _]; _] | ||
1219 | 82..83 'b': [[&str; _]; _] | ||
1220 | 95..96 'd': [isize; _] | ||
1221 | 99..111 '[y, 1, 2, 3]': [isize; _] | ||
1222 | 100..101 'y': isize | ||
1223 | 103..104 '1': isize | ||
1224 | 106..107 '2': isize | ||
1225 | 109..110 '3': isize | ||
1226 | 121..122 'd': [isize; _] | ||
1227 | 125..137 '[1, y, 2, 3]': [isize; _] | ||
1228 | 126..127 '1': isize | ||
1229 | 129..130 'y': isize | ||
1230 | 132..133 '2': isize | ||
1231 | 135..136 '3': isize | ||
1232 | 147..148 'e': [isize; _] | ||
1233 | 151..154 '[y]': [isize; _] | ||
1234 | 152..153 'y': isize | ||
1235 | 164..165 'f': [[isize; _]; _] | ||
1236 | 168..174 '[d, d]': [[isize; _]; _] | ||
1237 | 169..170 'd': [isize; _] | ||
1238 | 172..173 'd': [isize; _] | ||
1239 | 184..185 'g': [[isize; _]; _] | ||
1240 | 188..194 '[e, e]': [[isize; _]; _] | ||
1241 | 189..190 'e': [isize; _] | ||
1242 | 192..193 'e': [isize; _] | ||
1243 | 205..206 'h': [i32; _] | ||
1244 | 209..215 '[1, 2]': [i32; _] | ||
1245 | 210..211 '1': i32 | ||
1246 | 213..214 '2': i32 | ||
1247 | 225..226 'i': [&str; _] | ||
1248 | 229..239 '["a", "b"]': [&str; _] | ||
1249 | 230..233 '"a"': &str | ||
1250 | 235..238 '"b"': &str | ||
1251 | 250..251 'b': [[&str; _]; _] | ||
1252 | 254..264 '[a, ["b"]]': [[&str; _]; _] | ||
1253 | 255..256 'a': [&str; _] | ||
1254 | 258..263 '["b"]': [&str; _] | ||
1255 | 259..262 '"b"': &str | ||
1256 | 274..275 'x': [u8; _] | ||
1257 | 287..289 '[]': [u8; _] | ||
1258 | "#]], | ||
1259 | ); | ||
1260 | } | ||
1261 | |||
1262 | #[test] | ||
1263 | fn infer_struct_generics() { | ||
1264 | check_infer( | ||
1265 | r#" | ||
1266 | struct A<T> { | ||
1267 | x: T, | ||
1268 | } | ||
1269 | |||
1270 | fn test(a1: A<u32>, i: i32) { | ||
1271 | a1.x; | ||
1272 | let a2 = A { x: i }; | ||
1273 | a2.x; | ||
1274 | let a3 = A::<i128> { x: 1 }; | ||
1275 | a3.x; | ||
1276 | } | ||
1277 | "#, | ||
1278 | expect![[r#" | ||
1279 | 35..37 'a1': A<u32> | ||
1280 | 47..48 'i': i32 | ||
1281 | 55..146 '{ ...3.x; }': () | ||
1282 | 61..63 'a1': A<u32> | ||
1283 | 61..65 'a1.x': u32 | ||
1284 | 75..77 'a2': A<i32> | ||
1285 | 80..90 'A { x: i }': A<i32> | ||
1286 | 87..88 'i': i32 | ||
1287 | 96..98 'a2': A<i32> | ||
1288 | 96..100 'a2.x': i32 | ||
1289 | 110..112 'a3': A<i128> | ||
1290 | 115..133 'A::<i1...x: 1 }': A<i128> | ||
1291 | 130..131 '1': i128 | ||
1292 | 139..141 'a3': A<i128> | ||
1293 | 139..143 'a3.x': i128 | ||
1294 | "#]], | ||
1295 | ); | ||
1296 | } | ||
1297 | |||
1298 | #[test] | ||
1299 | fn infer_tuple_struct_generics() { | ||
1300 | check_infer( | ||
1301 | r#" | ||
1302 | struct A<T>(T); | ||
1303 | enum Option<T> { Some(T), None } | ||
1304 | use Option::*; | ||
1305 | |||
1306 | fn test() { | ||
1307 | A(42); | ||
1308 | A(42u128); | ||
1309 | Some("x"); | ||
1310 | Option::Some("x"); | ||
1311 | None; | ||
1312 | let x: Option<i64> = None; | ||
1313 | } | ||
1314 | "#, | ||
1315 | expect![[r#" | ||
1316 | 75..183 '{ ...one; }': () | ||
1317 | 81..82 'A': A<i32>(i32) -> A<i32> | ||
1318 | 81..86 'A(42)': A<i32> | ||
1319 | 83..85 '42': i32 | ||
1320 | 92..93 'A': A<u128>(u128) -> A<u128> | ||
1321 | 92..101 'A(42u128)': A<u128> | ||
1322 | 94..100 '42u128': u128 | ||
1323 | 107..111 'Some': Some<&str>(&str) -> Option<&str> | ||
1324 | 107..116 'Some("x")': Option<&str> | ||
1325 | 112..115 '"x"': &str | ||
1326 | 122..134 'Option::Some': Some<&str>(&str) -> Option<&str> | ||
1327 | 122..139 'Option...e("x")': Option<&str> | ||
1328 | 135..138 '"x"': &str | ||
1329 | 145..149 'None': Option<{unknown}> | ||
1330 | 159..160 'x': Option<i64> | ||
1331 | 176..180 'None': Option<i64> | ||
1332 | "#]], | ||
1333 | ); | ||
1334 | } | ||
1335 | |||
1336 | #[test] | ||
1337 | fn infer_function_generics() { | ||
1338 | check_infer( | ||
1339 | r#" | ||
1340 | fn id<T>(t: T) -> T { t } | ||
1341 | |||
1342 | fn test() { | ||
1343 | id(1u32); | ||
1344 | id::<i128>(1); | ||
1345 | let x: u64 = id(1); | ||
1346 | } | ||
1347 | "#, | ||
1348 | expect![[r#" | ||
1349 | 9..10 't': T | ||
1350 | 20..25 '{ t }': T | ||
1351 | 22..23 't': T | ||
1352 | 37..97 '{ ...(1); }': () | ||
1353 | 43..45 'id': fn id<u32>(u32) -> u32 | ||
1354 | 43..51 'id(1u32)': u32 | ||
1355 | 46..50 '1u32': u32 | ||
1356 | 57..67 'id::<i128>': fn id<i128>(i128) -> i128 | ||
1357 | 57..70 'id::<i128>(1)': i128 | ||
1358 | 68..69 '1': i128 | ||
1359 | 80..81 'x': u64 | ||
1360 | 89..91 'id': fn id<u64>(u64) -> u64 | ||
1361 | 89..94 'id(1)': u64 | ||
1362 | 92..93 '1': u64 | ||
1363 | "#]], | ||
1364 | ); | ||
1365 | } | ||
1366 | |||
1367 | #[test] | ||
1368 | fn infer_impl_generics_basic() { | ||
1369 | check_infer( | ||
1370 | r#" | ||
1371 | struct A<T1, T2> { | ||
1372 | x: T1, | ||
1373 | y: T2, | ||
1374 | } | ||
1375 | impl<Y, X> A<X, Y> { | ||
1376 | fn x(self) -> X { | ||
1377 | self.x | ||
1378 | } | ||
1379 | fn y(self) -> Y { | ||
1380 | self.y | ||
1381 | } | ||
1382 | fn z<T>(self, t: T) -> (X, Y, T) { | ||
1383 | (self.x, self.y, t) | ||
1384 | } | ||
1385 | } | ||
1386 | |||
1387 | fn test() -> i128 { | ||
1388 | let a = A { x: 1u64, y: 1i64 }; | ||
1389 | a.x(); | ||
1390 | a.y(); | ||
1391 | a.z(1i128); | ||
1392 | a.z::<u128>(1); | ||
1393 | } | ||
1394 | "#, | ||
1395 | expect![[r#" | ||
1396 | 73..77 'self': A<X, Y> | ||
1397 | 84..106 '{ ... }': X | ||
1398 | 94..98 'self': A<X, Y> | ||
1399 | 94..100 'self.x': X | ||
1400 | 116..120 'self': A<X, Y> | ||
1401 | 127..149 '{ ... }': Y | ||
1402 | 137..141 'self': A<X, Y> | ||
1403 | 137..143 'self.y': Y | ||
1404 | 162..166 'self': A<X, Y> | ||
1405 | 168..169 't': T | ||
1406 | 187..222 '{ ... }': (X, Y, T) | ||
1407 | 197..216 '(self.....y, t)': (X, Y, T) | ||
1408 | 198..202 'self': A<X, Y> | ||
1409 | 198..204 'self.x': X | ||
1410 | 206..210 'self': A<X, Y> | ||
1411 | 206..212 'self.y': Y | ||
1412 | 214..215 't': T | ||
1413 | 244..341 '{ ...(1); }': () | ||
1414 | 254..255 'a': A<u64, i64> | ||
1415 | 258..280 'A { x:...1i64 }': A<u64, i64> | ||
1416 | 265..269 '1u64': u64 | ||
1417 | 274..278 '1i64': i64 | ||
1418 | 286..287 'a': A<u64, i64> | ||
1419 | 286..291 'a.x()': u64 | ||
1420 | 297..298 'a': A<u64, i64> | ||
1421 | 297..302 'a.y()': i64 | ||
1422 | 308..309 'a': A<u64, i64> | ||
1423 | 308..318 'a.z(1i128)': (u64, i64, i128) | ||
1424 | 312..317 '1i128': i128 | ||
1425 | 324..325 'a': A<u64, i64> | ||
1426 | 324..338 'a.z::<u128>(1)': (u64, i64, u128) | ||
1427 | 336..337 '1': u128 | ||
1428 | "#]], | ||
1429 | ); | ||
1430 | } | ||
1431 | |||
1432 | #[test] | ||
1433 | fn infer_impl_generics_with_autoderef() { | ||
1434 | check_infer( | ||
1435 | r#" | ||
1436 | enum Option<T> { | ||
1437 | Some(T), | ||
1438 | None, | ||
1439 | } | ||
1440 | impl<T> Option<T> { | ||
1441 | fn as_ref(&self) -> Option<&T> {} | ||
1442 | } | ||
1443 | fn test(o: Option<u32>) { | ||
1444 | (&o).as_ref(); | ||
1445 | o.as_ref(); | ||
1446 | } | ||
1447 | "#, | ||
1448 | expect![[r#" | ||
1449 | 77..81 'self': &Option<T> | ||
1450 | 97..99 '{}': () | ||
1451 | 110..111 'o': Option<u32> | ||
1452 | 126..164 '{ ...f(); }': () | ||
1453 | 132..145 '(&o).as_ref()': Option<&u32> | ||
1454 | 133..135 '&o': &Option<u32> | ||
1455 | 134..135 'o': Option<u32> | ||
1456 | 151..152 'o': Option<u32> | ||
1457 | 151..161 'o.as_ref()': Option<&u32> | ||
1458 | "#]], | ||
1459 | ); | ||
1460 | } | ||
1461 | |||
1462 | #[test] | ||
1463 | fn infer_generic_chain() { | ||
1464 | check_infer( | ||
1465 | r#" | ||
1466 | struct A<T> { | ||
1467 | x: T, | ||
1468 | } | ||
1469 | impl<T2> A<T2> { | ||
1470 | fn x(self) -> T2 { | ||
1471 | self.x | ||
1472 | } | ||
1473 | } | ||
1474 | fn id<T>(t: T) -> T { t } | ||
1475 | |||
1476 | fn test() -> i128 { | ||
1477 | let x = 1; | ||
1478 | let y = id(x); | ||
1479 | let a = A { x: id(y) }; | ||
1480 | let z = id(a.x); | ||
1481 | let b = A { x: z }; | ||
1482 | b.x() | ||
1483 | } | ||
1484 | "#, | ||
1485 | expect![[r#" | ||
1486 | 52..56 'self': A<T2> | ||
1487 | 64..86 '{ ... }': T2 | ||
1488 | 74..78 'self': A<T2> | ||
1489 | 74..80 'self.x': T2 | ||
1490 | 98..99 't': T | ||
1491 | 109..114 '{ t }': T | ||
1492 | 111..112 't': T | ||
1493 | 134..254 '{ ....x() }': i128 | ||
1494 | 144..145 'x': i128 | ||
1495 | 148..149 '1': i128 | ||
1496 | 159..160 'y': i128 | ||
1497 | 163..165 'id': fn id<i128>(i128) -> i128 | ||
1498 | 163..168 'id(x)': i128 | ||
1499 | 166..167 'x': i128 | ||
1500 | 178..179 'a': A<i128> | ||
1501 | 182..196 'A { x: id(y) }': A<i128> | ||
1502 | 189..191 'id': fn id<i128>(i128) -> i128 | ||
1503 | 189..194 'id(y)': i128 | ||
1504 | 192..193 'y': i128 | ||
1505 | 206..207 'z': i128 | ||
1506 | 210..212 'id': fn id<i128>(i128) -> i128 | ||
1507 | 210..217 'id(a.x)': i128 | ||
1508 | 213..214 'a': A<i128> | ||
1509 | 213..216 'a.x': i128 | ||
1510 | 227..228 'b': A<i128> | ||
1511 | 231..241 'A { x: z }': A<i128> | ||
1512 | 238..239 'z': i128 | ||
1513 | 247..248 'b': A<i128> | ||
1514 | 247..252 'b.x()': i128 | ||
1515 | "#]], | ||
1516 | ); | ||
1517 | } | ||
1518 | |||
1519 | #[test] | ||
1520 | fn infer_associated_const() { | ||
1521 | check_infer( | ||
1522 | r#" | ||
1523 | struct Struct; | ||
1524 | |||
1525 | impl Struct { | ||
1526 | const FOO: u32 = 1; | ||
1527 | } | ||
1528 | |||
1529 | enum Enum {} | ||
1530 | |||
1531 | impl Enum { | ||
1532 | const BAR: u32 = 2; | ||
1533 | } | ||
1534 | |||
1535 | trait Trait { | ||
1536 | const ID: u32; | ||
1537 | } | ||
1538 | |||
1539 | struct TraitTest; | ||
1540 | |||
1541 | impl Trait for TraitTest { | ||
1542 | const ID: u32 = 5; | ||
1543 | } | ||
1544 | |||
1545 | fn test() { | ||
1546 | let x = Struct::FOO; | ||
1547 | let y = Enum::BAR; | ||
1548 | let z = TraitTest::ID; | ||
1549 | } | ||
1550 | "#, | ||
1551 | expect![[r#" | ||
1552 | 51..52 '1': u32 | ||
1553 | 104..105 '2': u32 | ||
1554 | 212..213 '5': u32 | ||
1555 | 228..306 '{ ...:ID; }': () | ||
1556 | 238..239 'x': u32 | ||
1557 | 242..253 'Struct::FOO': u32 | ||
1558 | 263..264 'y': u32 | ||
1559 | 267..276 'Enum::BAR': u32 | ||
1560 | 286..287 'z': u32 | ||
1561 | 290..303 'TraitTest::ID': u32 | ||
1562 | "#]], | ||
1563 | ); | ||
1564 | } | ||
1565 | |||
1566 | #[test] | ||
1567 | fn infer_type_alias() { | ||
1568 | check_infer( | ||
1569 | r#" | ||
1570 | struct A<X, Y> { x: X, y: Y } | ||
1571 | type Foo = A<u32, i128>; | ||
1572 | type Bar<T> = A<T, u128>; | ||
1573 | type Baz<U, V> = A<V, U>; | ||
1574 | fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) { | ||
1575 | x.x; | ||
1576 | x.y; | ||
1577 | y.x; | ||
1578 | y.y; | ||
1579 | z.x; | ||
1580 | z.y; | ||
1581 | } | ||
1582 | "#, | ||
1583 | expect![[r#" | ||
1584 | 115..116 'x': A<u32, i128> | ||
1585 | 123..124 'y': A<&str, u128> | ||
1586 | 137..138 'z': A<u8, i8> | ||
1587 | 153..210 '{ ...z.y; }': () | ||
1588 | 159..160 'x': A<u32, i128> | ||
1589 | 159..162 'x.x': u32 | ||
1590 | 168..169 'x': A<u32, i128> | ||
1591 | 168..171 'x.y': i128 | ||
1592 | 177..178 'y': A<&str, u128> | ||
1593 | 177..180 'y.x': &str | ||
1594 | 186..187 'y': A<&str, u128> | ||
1595 | 186..189 'y.y': u128 | ||
1596 | 195..196 'z': A<u8, i8> | ||
1597 | 195..198 'z.x': u8 | ||
1598 | 204..205 'z': A<u8, i8> | ||
1599 | 204..207 'z.y': i8 | ||
1600 | "#]], | ||
1601 | ) | ||
1602 | } | ||
1603 | |||
1604 | #[test] | ||
1605 | fn recursive_type_alias() { | ||
1606 | check_infer( | ||
1607 | r#" | ||
1608 | struct A<X> {} | ||
1609 | type Foo = Foo; | ||
1610 | type Bar = A<Bar>; | ||
1611 | fn test(x: Foo) {} | ||
1612 | "#, | ||
1613 | expect![[r#" | ||
1614 | 58..59 'x': {unknown} | ||
1615 | 66..68 '{}': () | ||
1616 | "#]], | ||
1617 | ) | ||
1618 | } | ||
1619 | |||
1620 | #[test] | ||
1621 | fn infer_type_param() { | ||
1622 | check_infer( | ||
1623 | r#" | ||
1624 | fn id<T>(x: T) -> T { | ||
1625 | x | ||
1626 | } | ||
1627 | |||
1628 | fn clone<T>(x: &T) -> T { | ||
1629 | *x | ||
1630 | } | ||
1631 | |||
1632 | fn test() { | ||
1633 | let y = 10u32; | ||
1634 | id(y); | ||
1635 | let x: bool = clone(z); | ||
1636 | id::<i128>(1); | ||
1637 | } | ||
1638 | "#, | ||
1639 | expect![[r#" | ||
1640 | 9..10 'x': T | ||
1641 | 20..29 '{ x }': T | ||
1642 | 26..27 'x': T | ||
1643 | 43..44 'x': &T | ||
1644 | 55..65 '{ *x }': T | ||
1645 | 61..63 '*x': T | ||
1646 | 62..63 'x': &T | ||
1647 | 77..157 '{ ...(1); }': () | ||
1648 | 87..88 'y': u32 | ||
1649 | 91..96 '10u32': u32 | ||
1650 | 102..104 'id': fn id<u32>(u32) -> u32 | ||
1651 | 102..107 'id(y)': u32 | ||
1652 | 105..106 'y': u32 | ||
1653 | 117..118 'x': bool | ||
1654 | 127..132 'clone': fn clone<bool>(&bool) -> bool | ||
1655 | 127..135 'clone(z)': bool | ||
1656 | 133..134 'z': &bool | ||
1657 | 141..151 'id::<i128>': fn id<i128>(i128) -> i128 | ||
1658 | 141..154 'id::<i128>(1)': i128 | ||
1659 | 152..153 '1': i128 | ||
1660 | "#]], | ||
1661 | ); | ||
1662 | } | ||
1663 | |||
1664 | #[test] | ||
1665 | fn infer_const() { | ||
1666 | check_infer( | ||
1667 | r#" | ||
1668 | struct Foo; | ||
1669 | impl Foo { const ASSOC_CONST: u32 = 0; } | ||
1670 | const GLOBAL_CONST: u32 = 101; | ||
1671 | fn test() { | ||
1672 | const LOCAL_CONST: u32 = 99; | ||
1673 | let x = LOCAL_CONST; | ||
1674 | let z = GLOBAL_CONST; | ||
1675 | let id = Foo::ASSOC_CONST; | ||
1676 | } | ||
1677 | "#, | ||
1678 | expect![[r#" | ||
1679 | 48..49 '0': u32 | ||
1680 | 79..82 '101': u32 | ||
1681 | 94..212 '{ ...NST; }': () | ||
1682 | 137..138 'x': u32 | ||
1683 | 141..152 'LOCAL_CONST': u32 | ||
1684 | 162..163 'z': u32 | ||
1685 | 166..178 'GLOBAL_CONST': u32 | ||
1686 | 188..190 'id': u32 | ||
1687 | 193..209 'Foo::A..._CONST': u32 | ||
1688 | 125..127 '99': u32 | ||
1689 | "#]], | ||
1690 | ); | ||
1691 | } | ||
1692 | |||
1693 | #[test] | ||
1694 | fn infer_static() { | ||
1695 | check_infer( | ||
1696 | r#" | ||
1697 | static GLOBAL_STATIC: u32 = 101; | ||
1698 | static mut GLOBAL_STATIC_MUT: u32 = 101; | ||
1699 | fn test() { | ||
1700 | static LOCAL_STATIC: u32 = 99; | ||
1701 | static mut LOCAL_STATIC_MUT: u32 = 99; | ||
1702 | let x = LOCAL_STATIC; | ||
1703 | let y = LOCAL_STATIC_MUT; | ||
1704 | let z = GLOBAL_STATIC; | ||
1705 | let w = GLOBAL_STATIC_MUT; | ||
1706 | } | ||
1707 | "#, | ||
1708 | expect![[r#" | ||
1709 | 28..31 '101': u32 | ||
1710 | 69..72 '101': u32 | ||
1711 | 84..279 '{ ...MUT; }': () | ||
1712 | 172..173 'x': u32 | ||
1713 | 176..188 'LOCAL_STATIC': u32 | ||
1714 | 198..199 'y': u32 | ||
1715 | 202..218 'LOCAL_...IC_MUT': u32 | ||
1716 | 228..229 'z': u32 | ||
1717 | 232..245 'GLOBAL_STATIC': u32 | ||
1718 | 255..256 'w': u32 | ||
1719 | 259..276 'GLOBAL...IC_MUT': u32 | ||
1720 | 117..119 '99': u32 | ||
1721 | 160..162 '99': u32 | ||
1722 | "#]], | ||
1723 | ); | ||
1724 | } | ||
1725 | |||
1726 | #[test] | ||
1727 | fn shadowing_primitive() { | ||
1728 | check_types( | ||
1729 | r#" | ||
1730 | struct i32; | ||
1731 | struct Foo; | ||
1732 | |||
1733 | impl i32 { fn foo(&self) -> Foo { Foo } } | ||
1734 | |||
1735 | fn main() { | ||
1736 | let x: i32 = i32; | ||
1737 | x.foo(); | ||
1738 | //^ Foo | ||
1739 | }"#, | ||
1740 | ); | ||
1741 | } | ||
1742 | |||
1743 | #[test] | ||
1744 | fn not_shadowing_primitive_by_module() { | ||
1745 | check_types( | ||
1746 | r#" | ||
1747 | //- /str.rs | ||
1748 | fn foo() {} | ||
1749 | |||
1750 | //- /main.rs | ||
1751 | mod str; | ||
1752 | fn foo() -> &'static str { "" } | ||
1753 | |||
1754 | fn main() { | ||
1755 | foo(); | ||
1756 | //^ &str | ||
1757 | }"#, | ||
1758 | ); | ||
1759 | } | ||
1760 | |||
1761 | #[test] | ||
1762 | fn not_shadowing_module_by_primitive() { | ||
1763 | check_types( | ||
1764 | r#" | ||
1765 | //- /str.rs | ||
1766 | fn foo() -> u32 {0} | ||
1767 | |||
1768 | //- /main.rs | ||
1769 | mod str; | ||
1770 | fn foo() -> &'static str { "" } | ||
1771 | |||
1772 | fn main() { | ||
1773 | str::foo(); | ||
1774 | //^ u32 | ||
1775 | }"#, | ||
1776 | ); | ||
1777 | } | ||
1778 | |||
1779 | // This test is actually testing the shadowing behavior within hir_def. It | ||
1780 | // lives here because the testing infrastructure in hir_def isn't currently | ||
1781 | // capable of asserting the necessary conditions. | ||
1782 | #[test] | ||
1783 | fn should_be_shadowing_imports() { | ||
1784 | check_types( | ||
1785 | r#" | ||
1786 | mod a { | ||
1787 | pub fn foo() -> i8 {0} | ||
1788 | pub struct foo { a: i8 } | ||
1789 | } | ||
1790 | mod b { pub fn foo () -> u8 {0} } | ||
1791 | mod c { pub struct foo { a: u8 } } | ||
1792 | mod d { | ||
1793 | pub use super::a::*; | ||
1794 | pub use super::c::foo; | ||
1795 | pub use super::b::foo; | ||
1796 | } | ||
1797 | |||
1798 | fn main() { | ||
1799 | d::foo(); | ||
1800 | //^ u8 | ||
1801 | d::foo{a:0}; | ||
1802 | //^ u8 | ||
1803 | }"#, | ||
1804 | ); | ||
1805 | } | ||
1806 | |||
1807 | #[test] | ||
1808 | fn closure_return() { | ||
1809 | check_infer( | ||
1810 | r#" | ||
1811 | fn foo() -> u32 { | ||
1812 | let x = || -> usize { return 1; }; | ||
1813 | } | ||
1814 | "#, | ||
1815 | expect![[r#" | ||
1816 | 16..58 '{ ...; }; }': () | ||
1817 | 26..27 'x': || -> usize | ||
1818 | 30..55 '|| -> ...n 1; }': || -> usize | ||
1819 | 42..55 '{ return 1; }': usize | ||
1820 | 44..52 'return 1': ! | ||
1821 | 51..52 '1': usize | ||
1822 | "#]], | ||
1823 | ); | ||
1824 | } | ||
1825 | |||
1826 | #[test] | ||
1827 | fn closure_return_unit() { | ||
1828 | check_infer( | ||
1829 | r#" | ||
1830 | fn foo() -> u32 { | ||
1831 | let x = || { return; }; | ||
1832 | } | ||
1833 | "#, | ||
1834 | expect![[r#" | ||
1835 | 16..47 '{ ...; }; }': () | ||
1836 | 26..27 'x': || -> () | ||
1837 | 30..44 '|| { return; }': || -> () | ||
1838 | 33..44 '{ return; }': () | ||
1839 | 35..41 'return': ! | ||
1840 | "#]], | ||
1841 | ); | ||
1842 | } | ||
1843 | |||
1844 | #[test] | ||
1845 | fn closure_return_inferred() { | ||
1846 | check_infer( | ||
1847 | r#" | ||
1848 | fn foo() -> u32 { | ||
1849 | let x = || { "test" }; | ||
1850 | } | ||
1851 | "#, | ||
1852 | expect![[r#" | ||
1853 | 16..46 '{ ..." }; }': () | ||
1854 | 26..27 'x': || -> &str | ||
1855 | 30..43 '|| { "test" }': || -> &str | ||
1856 | 33..43 '{ "test" }': &str | ||
1857 | 35..41 '"test"': &str | ||
1858 | "#]], | ||
1859 | ); | ||
1860 | } | ||
1861 | |||
1862 | #[test] | ||
1863 | fn fn_pointer_return() { | ||
1864 | check_infer( | ||
1865 | r#" | ||
1866 | struct Vtable { | ||
1867 | method: fn(), | ||
1868 | } | ||
1869 | |||
1870 | fn main() { | ||
1871 | let vtable = Vtable { method: || {} }; | ||
1872 | let m = vtable.method; | ||
1873 | } | ||
1874 | "#, | ||
1875 | expect![[r#" | ||
1876 | 47..120 '{ ...hod; }': () | ||
1877 | 57..63 'vtable': Vtable | ||
1878 | 66..90 'Vtable...| {} }': Vtable | ||
1879 | 83..88 '|| {}': || -> () | ||
1880 | 86..88 '{}': () | ||
1881 | 100..101 'm': fn() | ||
1882 | 104..110 'vtable': Vtable | ||
1883 | 104..117 'vtable.method': fn() | ||
1884 | "#]], | ||
1885 | ); | ||
1886 | } | ||
1887 | |||
1888 | #[test] | ||
1889 | fn effects_smoke_test() { | ||
1890 | check_infer( | ||
1891 | r#" | ||
1892 | fn main() { | ||
1893 | let x = unsafe { 92 }; | ||
1894 | let y = async { async { () }.await }; | ||
1895 | let z = try { () }; | ||
1896 | let t = 'a: { 92 }; | ||
1897 | } | ||
1898 | "#, | ||
1899 | expect![[r#" | ||
1900 | 10..130 '{ ...2 }; }': () | ||
1901 | 20..21 'x': i32 | ||
1902 | 24..37 'unsafe { 92 }': i32 | ||
1903 | 31..37 '{ 92 }': i32 | ||
1904 | 33..35 '92': i32 | ||
1905 | 47..48 'y': {unknown} | ||
1906 | 57..79 '{ asyn...wait }': {unknown} | ||
1907 | 59..77 'async ....await': {unknown} | ||
1908 | 65..71 '{ () }': () | ||
1909 | 67..69 '()': () | ||
1910 | 89..90 'z': {unknown} | ||
1911 | 93..103 'try { () }': {unknown} | ||
1912 | 97..103 '{ () }': () | ||
1913 | 99..101 '()': () | ||
1914 | 113..114 't': i32 | ||
1915 | 121..127 '{ 92 }': i32 | ||
1916 | 123..125 '92': i32 | ||
1917 | "#]], | ||
1918 | ) | ||
1919 | } | ||
1920 | |||
1921 | #[test] | ||
1922 | fn infer_generic_from_later_assignment() { | ||
1923 | check_infer( | ||
1924 | r#" | ||
1925 | enum Option<T> { Some(T), None } | ||
1926 | use Option::*; | ||
1927 | |||
1928 | fn test() { | ||
1929 | let mut end = None; | ||
1930 | loop { | ||
1931 | end = Some(true); | ||
1932 | } | ||
1933 | } | ||
1934 | "#, | ||
1935 | expect![[r#" | ||
1936 | 59..129 '{ ... } }': () | ||
1937 | 69..76 'mut end': Option<bool> | ||
1938 | 79..83 'None': Option<bool> | ||
1939 | 89..127 'loop {... }': ! | ||
1940 | 94..127 '{ ... }': () | ||
1941 | 104..107 'end': Option<bool> | ||
1942 | 104..120 'end = ...(true)': () | ||
1943 | 110..114 'Some': Some<bool>(bool) -> Option<bool> | ||
1944 | 110..120 'Some(true)': Option<bool> | ||
1945 | 115..119 'true': bool | ||
1946 | "#]], | ||
1947 | ); | ||
1948 | } | ||
1949 | |||
1950 | #[test] | ||
1951 | fn infer_loop_break_with_val() { | ||
1952 | check_infer( | ||
1953 | r#" | ||
1954 | enum Option<T> { Some(T), None } | ||
1955 | use Option::*; | ||
1956 | |||
1957 | fn test() { | ||
1958 | let x = loop { | ||
1959 | if false { | ||
1960 | break None; | ||
1961 | } | ||
1962 | |||
1963 | break Some(true); | ||
1964 | }; | ||
1965 | } | ||
1966 | "#, | ||
1967 | expect![[r#" | ||
1968 | 59..168 '{ ... }; }': () | ||
1969 | 69..70 'x': Option<bool> | ||
1970 | 73..165 'loop {... }': Option<bool> | ||
1971 | 78..165 '{ ... }': () | ||
1972 | 88..132 'if fal... }': () | ||
1973 | 91..96 'false': bool | ||
1974 | 97..132 '{ ... }': () | ||
1975 | 111..121 'break None': ! | ||
1976 | 117..121 'None': Option<bool> | ||
1977 | 142..158 'break ...(true)': ! | ||
1978 | 148..152 'Some': Some<bool>(bool) -> Option<bool> | ||
1979 | 148..158 'Some(true)': Option<bool> | ||
1980 | 153..157 'true': bool | ||
1981 | "#]], | ||
1982 | ); | ||
1983 | } | ||
1984 | |||
1985 | #[test] | ||
1986 | fn infer_loop_break_without_val() { | ||
1987 | check_infer( | ||
1988 | r#" | ||
1989 | enum Option<T> { Some(T), None } | ||
1990 | use Option::*; | ||
1991 | |||
1992 | fn test() { | ||
1993 | let x = loop { | ||
1994 | if false { | ||
1995 | break; | ||
1996 | } | ||
1997 | }; | ||
1998 | } | ||
1999 | "#, | ||
2000 | expect![[r#" | ||
2001 | 59..136 '{ ... }; }': () | ||
2002 | 69..70 'x': () | ||
2003 | 73..133 'loop {... }': () | ||
2004 | 78..133 '{ ... }': () | ||
2005 | 88..127 'if fal... }': () | ||
2006 | 91..96 'false': bool | ||
2007 | 97..127 '{ ... }': () | ||
2008 | 111..116 'break': ! | ||
2009 | "#]], | ||
2010 | ); | ||
2011 | } | ||
2012 | |||
2013 | #[test] | ||
2014 | fn infer_labelled_break_with_val() { | ||
2015 | check_infer( | ||
2016 | r#" | ||
2017 | fn foo() { | ||
2018 | let _x = || 'outer: loop { | ||
2019 | let inner = 'inner: loop { | ||
2020 | let i = Default::default(); | ||
2021 | if (break 'outer i) { | ||
2022 | loop { break 'inner 5i8; }; | ||
2023 | } else if true { | ||
2024 | break 'inner 6; | ||
2025 | } | ||
2026 | break 7; | ||
2027 | }; | ||
2028 | break inner < 8; | ||
2029 | }; | ||
2030 | } | ||
2031 | "#, | ||
2032 | expect![[r#" | ||
2033 | 9..335 '{ ... }; }': () | ||
2034 | 19..21 '_x': || -> bool | ||
2035 | 24..332 '|| 'ou... }': || -> bool | ||
2036 | 27..332 ''outer... }': bool | ||
2037 | 40..332 '{ ... }': () | ||
2038 | 54..59 'inner': i8 | ||
2039 | 62..300 ''inner... }': i8 | ||
2040 | 75..300 '{ ... }': () | ||
2041 | 93..94 'i': bool | ||
2042 | 97..113 'Defaul...efault': {unknown} | ||
2043 | 97..115 'Defaul...ault()': bool | ||
2044 | 129..269 'if (br... }': () | ||
2045 | 133..147 'break 'outer i': ! | ||
2046 | 146..147 'i': bool | ||
2047 | 149..208 '{ ... }': () | ||
2048 | 167..193 'loop {...5i8; }': ! | ||
2049 | 172..193 '{ brea...5i8; }': () | ||
2050 | 174..190 'break ...er 5i8': ! | ||
2051 | 187..190 '5i8': i8 | ||
2052 | 214..269 'if tru... }': () | ||
2053 | 217..221 'true': bool | ||
2054 | 222..269 '{ ... }': () | ||
2055 | 240..254 'break 'inner 6': ! | ||
2056 | 253..254 '6': i8 | ||
2057 | 282..289 'break 7': ! | ||
2058 | 288..289 '7': i8 | ||
2059 | 310..325 'break inner < 8': ! | ||
2060 | 316..321 'inner': i8 | ||
2061 | 316..325 'inner < 8': bool | ||
2062 | 324..325 '8': i8 | ||
2063 | "#]], | ||
2064 | ); | ||
2065 | } | ||
2066 | |||
2067 | #[test] | ||
2068 | fn generic_default() { | ||
2069 | check_infer( | ||
2070 | r#" | ||
2071 | struct Thing<T = ()> { t: T } | ||
2072 | enum OtherThing<T = ()> { | ||
2073 | One { t: T }, | ||
2074 | Two(T), | ||
2075 | } | ||
2076 | |||
2077 | fn test(t1: Thing, t2: OtherThing, t3: Thing<i32>, t4: OtherThing<i32>) { | ||
2078 | t1.t; | ||
2079 | t3.t; | ||
2080 | match t2 { | ||
2081 | OtherThing::One { t } => { t; }, | ||
2082 | OtherThing::Two(t) => { t; }, | ||
2083 | } | ||
2084 | match t4 { | ||
2085 | OtherThing::One { t } => { t; }, | ||
2086 | OtherThing::Two(t) => { t; }, | ||
2087 | } | ||
2088 | } | ||
2089 | "#, | ||
2090 | expect![[r#" | ||
2091 | 97..99 't1': Thing<()> | ||
2092 | 108..110 't2': OtherThing<()> | ||
2093 | 124..126 't3': Thing<i32> | ||
2094 | 140..142 't4': OtherThing<i32> | ||
2095 | 161..384 '{ ... } }': () | ||
2096 | 167..169 't1': Thing<()> | ||
2097 | 167..171 't1.t': () | ||
2098 | 177..179 't3': Thing<i32> | ||
2099 | 177..181 't3.t': i32 | ||
2100 | 187..282 'match ... }': () | ||
2101 | 193..195 't2': OtherThing<()> | ||
2102 | 206..227 'OtherT... { t }': OtherThing<()> | ||
2103 | 224..225 't': () | ||
2104 | 231..237 '{ t; }': () | ||
2105 | 233..234 't': () | ||
2106 | 247..265 'OtherT...Two(t)': OtherThing<()> | ||
2107 | 263..264 't': () | ||
2108 | 269..275 '{ t; }': () | ||
2109 | 271..272 't': () | ||
2110 | 287..382 'match ... }': () | ||
2111 | 293..295 't4': OtherThing<i32> | ||
2112 | 306..327 'OtherT... { t }': OtherThing<i32> | ||
2113 | 324..325 't': i32 | ||
2114 | 331..337 '{ t; }': () | ||
2115 | 333..334 't': i32 | ||
2116 | 347..365 'OtherT...Two(t)': OtherThing<i32> | ||
2117 | 363..364 't': i32 | ||
2118 | 369..375 '{ t; }': () | ||
2119 | 371..372 't': i32 | ||
2120 | "#]], | ||
2121 | ); | ||
2122 | } | ||
2123 | |||
2124 | #[test] | ||
2125 | fn generic_default_in_struct_literal() { | ||
2126 | check_infer( | ||
2127 | r#" | ||
2128 | struct Thing<T = ()> { t: T } | ||
2129 | enum OtherThing<T = ()> { | ||
2130 | One { t: T }, | ||
2131 | Two(T), | ||
2132 | } | ||
2133 | |||
2134 | fn test() { | ||
2135 | let x = Thing { t: loop {} }; | ||
2136 | let y = Thing { t: () }; | ||
2137 | let z = Thing { t: 1i32 }; | ||
2138 | if let Thing { t } = z { | ||
2139 | t; | ||
2140 | } | ||
2141 | |||
2142 | let a = OtherThing::One { t: 1i32 }; | ||
2143 | let b = OtherThing::Two(1i32); | ||
2144 | } | ||
2145 | "#, | ||
2146 | expect![[r#" | ||
2147 | 99..319 '{ ...32); }': () | ||
2148 | 109..110 'x': Thing<!> | ||
2149 | 113..133 'Thing ...p {} }': Thing<!> | ||
2150 | 124..131 'loop {}': ! | ||
2151 | 129..131 '{}': () | ||
2152 | 143..144 'y': Thing<()> | ||
2153 | 147..162 'Thing { t: () }': Thing<()> | ||
2154 | 158..160 '()': () | ||
2155 | 172..173 'z': Thing<i32> | ||
2156 | 176..193 'Thing ...1i32 }': Thing<i32> | ||
2157 | 187..191 '1i32': i32 | ||
2158 | 199..240 'if let... }': () | ||
2159 | 206..217 'Thing { t }': Thing<i32> | ||
2160 | 214..215 't': i32 | ||
2161 | 220..221 'z': Thing<i32> | ||
2162 | 222..240 '{ ... }': () | ||
2163 | 232..233 't': i32 | ||
2164 | 250..251 'a': OtherThing<i32> | ||
2165 | 254..281 'OtherT...1i32 }': OtherThing<i32> | ||
2166 | 275..279 '1i32': i32 | ||
2167 | 291..292 'b': OtherThing<i32> | ||
2168 | 295..310 'OtherThing::Two': Two<i32>(i32) -> OtherThing<i32> | ||
2169 | 295..316 'OtherT...(1i32)': OtherThing<i32> | ||
2170 | 311..315 '1i32': i32 | ||
2171 | "#]], | ||
2172 | ); | ||
2173 | } | ||
2174 | |||
2175 | #[test] | ||
2176 | fn generic_default_depending_on_other_type_arg() { | ||
2177 | // FIXME: the {unknown} is a bug | ||
2178 | check_infer( | ||
2179 | r#" | ||
2180 | struct Thing<T = u128, F = fn() -> T> { t: T } | ||
2181 | |||
2182 | fn test(t1: Thing<u32>, t2: Thing) { | ||
2183 | t1; | ||
2184 | t2; | ||
2185 | Thing::<_> { t: 1u32 }; | ||
2186 | } | ||
2187 | "#, | ||
2188 | expect![[r#" | ||
2189 | 56..58 't1': Thing<u32, fn() -> u32> | ||
2190 | 72..74 't2': Thing<u128, fn() -> u128> | ||
2191 | 83..130 '{ ...2 }; }': () | ||
2192 | 89..91 't1': Thing<u32, fn() -> u32> | ||
2193 | 97..99 't2': Thing<u128, fn() -> u128> | ||
2194 | 105..127 'Thing:...1u32 }': Thing<u32, fn() -> {unknown}> | ||
2195 | 121..125 '1u32': u32 | ||
2196 | "#]], | ||
2197 | ); | ||
2198 | } | ||
2199 | |||
2200 | #[test] | ||
2201 | fn generic_default_depending_on_other_type_arg_forward() { | ||
2202 | // the {unknown} here is intentional, as defaults are not allowed to | ||
2203 | // refer to type parameters coming later | ||
2204 | check_infer( | ||
2205 | r#" | ||
2206 | struct Thing<F = fn() -> T, T = u128> { t: T } | ||
2207 | |||
2208 | fn test(t1: Thing) { | ||
2209 | t1; | ||
2210 | } | ||
2211 | "#, | ||
2212 | expect![[r#" | ||
2213 | 56..58 't1': Thing<fn() -> {unknown}, u128> | ||
2214 | 67..78 '{ t1; }': () | ||
2215 | 73..75 't1': Thing<fn() -> {unknown}, u128> | ||
2216 | "#]], | ||
2217 | ); | ||
2218 | } | ||
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs new file mode 100644 index 000000000..526e61caf --- /dev/null +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -0,0 +1,3113 @@ | |||
1 | use expect::expect; | ||
2 | use test_utils::mark; | ||
3 | |||
4 | use super::{check_infer, check_infer_with_mismatches, check_types}; | ||
5 | |||
6 | #[test] | ||
7 | fn infer_await() { | ||
8 | check_types( | ||
9 | r#" | ||
10 | //- /main.rs crate:main deps:core | ||
11 | struct IntFuture; | ||
12 | |||
13 | impl Future for IntFuture { | ||
14 | type Output = u64; | ||
15 | } | ||
16 | |||
17 | fn test() { | ||
18 | let r = IntFuture; | ||
19 | let v = r.await; | ||
20 | v; | ||
21 | } //^ u64 | ||
22 | |||
23 | //- /core.rs crate:core | ||
24 | #[prelude_import] use future::*; | ||
25 | mod future { | ||
26 | #[lang = "future_trait"] | ||
27 | trait Future { | ||
28 | type Output; | ||
29 | } | ||
30 | } | ||
31 | "#, | ||
32 | ); | ||
33 | } | ||
34 | |||
35 | #[test] | ||
36 | fn infer_async() { | ||
37 | check_types( | ||
38 | r#" | ||
39 | //- /main.rs crate:main deps:core | ||
40 | async fn foo() -> u64 { | ||
41 | 128 | ||
42 | } | ||
43 | |||
44 | fn test() { | ||
45 | let r = foo(); | ||
46 | let v = r.await; | ||
47 | v; | ||
48 | } //^ u64 | ||
49 | |||
50 | //- /core.rs crate:core | ||
51 | #[prelude_import] use future::*; | ||
52 | mod future { | ||
53 | #[lang = "future_trait"] | ||
54 | trait Future { | ||
55 | type Output; | ||
56 | } | ||
57 | } | ||
58 | "#, | ||
59 | ); | ||
60 | } | ||
61 | |||
62 | #[test] | ||
63 | fn infer_desugar_async() { | ||
64 | check_types( | ||
65 | r#" | ||
66 | //- /main.rs crate:main deps:core | ||
67 | async fn foo() -> u64 { | ||
68 | 128 | ||
69 | } | ||
70 | |||
71 | fn test() { | ||
72 | let r = foo(); | ||
73 | r; | ||
74 | } //^ impl Future<Output = u64> | ||
75 | |||
76 | //- /core.rs crate:core | ||
77 | #[prelude_import] use future::*; | ||
78 | mod future { | ||
79 | trait Future { | ||
80 | type Output; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | "#, | ||
85 | ); | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn infer_try() { | ||
90 | check_types( | ||
91 | r#" | ||
92 | //- /main.rs crate:main deps:core | ||
93 | fn test() { | ||
94 | let r: Result<i32, u64> = Result::Ok(1); | ||
95 | let v = r?; | ||
96 | v; | ||
97 | } //^ i32 | ||
98 | |||
99 | //- /core.rs crate:core | ||
100 | #[prelude_import] use ops::*; | ||
101 | mod ops { | ||
102 | trait Try { | ||
103 | type Ok; | ||
104 | type Error; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | #[prelude_import] use result::*; | ||
109 | mod result { | ||
110 | enum Result<O, E> { | ||
111 | Ok(O), | ||
112 | Err(E) | ||
113 | } | ||
114 | |||
115 | impl<O, E> crate::ops::Try for Result<O, E> { | ||
116 | type Ok = O; | ||
117 | type Error = E; | ||
118 | } | ||
119 | } | ||
120 | "#, | ||
121 | ); | ||
122 | } | ||
123 | |||
124 | #[test] | ||
125 | fn infer_for_loop() { | ||
126 | check_types( | ||
127 | r#" | ||
128 | //- /main.rs crate:main deps:core,alloc | ||
129 | use alloc::collections::Vec; | ||
130 | |||
131 | fn test() { | ||
132 | let v = Vec::new(); | ||
133 | v.push("foo"); | ||
134 | for x in v { | ||
135 | x; | ||
136 | } //^ &str | ||
137 | } | ||
138 | |||
139 | //- /core.rs crate:core | ||
140 | #[prelude_import] use iter::*; | ||
141 | mod iter { | ||
142 | trait IntoIterator { | ||
143 | type Item; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | //- /alloc.rs crate:alloc deps:core | ||
148 | mod collections { | ||
149 | struct Vec<T> {} | ||
150 | impl<T> Vec<T> { | ||
151 | fn new() -> Self { Vec {} } | ||
152 | fn push(&mut self, t: T) { } | ||
153 | } | ||
154 | |||
155 | impl<T> IntoIterator for Vec<T> { | ||
156 | type Item=T; | ||
157 | } | ||
158 | } | ||
159 | "#, | ||
160 | ); | ||
161 | } | ||
162 | |||
163 | #[test] | ||
164 | fn infer_ops_neg() { | ||
165 | check_types( | ||
166 | r#" | ||
167 | //- /main.rs crate:main deps:std | ||
168 | struct Bar; | ||
169 | struct Foo; | ||
170 | |||
171 | impl std::ops::Neg for Bar { | ||
172 | type Output = Foo; | ||
173 | } | ||
174 | |||
175 | fn test() { | ||
176 | let a = Bar; | ||
177 | let b = -a; | ||
178 | b; | ||
179 | } //^ Foo | ||
180 | |||
181 | //- /std.rs crate:std | ||
182 | #[prelude_import] use ops::*; | ||
183 | mod ops { | ||
184 | #[lang = "neg"] | ||
185 | pub trait Neg { | ||
186 | type Output; | ||
187 | } | ||
188 | } | ||
189 | "#, | ||
190 | ); | ||
191 | } | ||
192 | |||
193 | #[test] | ||
194 | fn infer_ops_not() { | ||
195 | check_types( | ||
196 | r#" | ||
197 | //- /main.rs crate:main deps:std | ||
198 | struct Bar; | ||
199 | struct Foo; | ||
200 | |||
201 | impl std::ops::Not for Bar { | ||
202 | type Output = Foo; | ||
203 | } | ||
204 | |||
205 | fn test() { | ||
206 | let a = Bar; | ||
207 | let b = !a; | ||
208 | b; | ||
209 | } //^ Foo | ||
210 | |||
211 | //- /std.rs crate:std | ||
212 | #[prelude_import] use ops::*; | ||
213 | mod ops { | ||
214 | #[lang = "not"] | ||
215 | pub trait Not { | ||
216 | type Output; | ||
217 | } | ||
218 | } | ||
219 | "#, | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | #[test] | ||
224 | fn infer_from_bound_1() { | ||
225 | check_infer( | ||
226 | r#" | ||
227 | trait Trait<T> {} | ||
228 | struct S<T>(T); | ||
229 | impl<U> Trait<U> for S<U> {} | ||
230 | fn foo<T: Trait<u32>>(t: T) {} | ||
231 | fn test() { | ||
232 | let s = S(unknown); | ||
233 | foo(s); | ||
234 | } | ||
235 | "#, | ||
236 | expect![[r#" | ||
237 | 85..86 't': T | ||
238 | 91..93 '{}': () | ||
239 | 104..143 '{ ...(s); }': () | ||
240 | 114..115 's': S<u32> | ||
241 | 118..119 'S': S<u32>(u32) -> S<u32> | ||
242 | 118..128 'S(unknown)': S<u32> | ||
243 | 120..127 'unknown': u32 | ||
244 | 134..137 'foo': fn foo<S<u32>>(S<u32>) | ||
245 | 134..140 'foo(s)': () | ||
246 | 138..139 's': S<u32> | ||
247 | "#]], | ||
248 | ); | ||
249 | } | ||
250 | |||
251 | #[test] | ||
252 | fn infer_from_bound_2() { | ||
253 | check_infer( | ||
254 | r#" | ||
255 | trait Trait<T> {} | ||
256 | struct S<T>(T); | ||
257 | impl<U> Trait<U> for S<U> {} | ||
258 | fn foo<U, T: Trait<U>>(t: T) -> U {} | ||
259 | fn test() { | ||
260 | let s = S(unknown); | ||
261 | let x: u32 = foo(s); | ||
262 | } | ||
263 | "#, | ||
264 | expect![[r#" | ||
265 | 86..87 't': T | ||
266 | 97..99 '{}': () | ||
267 | 110..162 '{ ...(s); }': () | ||
268 | 120..121 's': S<u32> | ||
269 | 124..125 'S': S<u32>(u32) -> S<u32> | ||
270 | 124..134 'S(unknown)': S<u32> | ||
271 | 126..133 'unknown': u32 | ||
272 | 144..145 'x': u32 | ||
273 | 153..156 'foo': fn foo<u32, S<u32>>(S<u32>) -> u32 | ||
274 | 153..159 'foo(s)': u32 | ||
275 | 157..158 's': S<u32> | ||
276 | "#]], | ||
277 | ); | ||
278 | } | ||
279 | |||
280 | #[test] | ||
281 | fn trait_default_method_self_bound_implements_trait() { | ||
282 | mark::check!(trait_self_implements_self); | ||
283 | check_infer( | ||
284 | r#" | ||
285 | trait Trait { | ||
286 | fn foo(&self) -> i64; | ||
287 | fn bar(&self) -> { | ||
288 | let x = self.foo(); | ||
289 | } | ||
290 | } | ||
291 | "#, | ||
292 | expect![[r#" | ||
293 | 26..30 'self': &Self | ||
294 | 52..56 'self': &Self | ||
295 | 61..96 '{ ... }': () | ||
296 | 75..76 'x': i64 | ||
297 | 79..83 'self': &Self | ||
298 | 79..89 'self.foo()': i64 | ||
299 | "#]], | ||
300 | ); | ||
301 | } | ||
302 | |||
303 | #[test] | ||
304 | fn trait_default_method_self_bound_implements_super_trait() { | ||
305 | check_infer( | ||
306 | r#" | ||
307 | trait SuperTrait { | ||
308 | fn foo(&self) -> i64; | ||
309 | } | ||
310 | trait Trait: SuperTrait { | ||
311 | fn bar(&self) -> { | ||
312 | let x = self.foo(); | ||
313 | } | ||
314 | } | ||
315 | "#, | ||
316 | expect![[r#" | ||
317 | 31..35 'self': &Self | ||
318 | 85..89 'self': &Self | ||
319 | 94..129 '{ ... }': () | ||
320 | 108..109 'x': i64 | ||
321 | 112..116 'self': &Self | ||
322 | 112..122 'self.foo()': i64 | ||
323 | "#]], | ||
324 | ); | ||
325 | } | ||
326 | |||
327 | #[test] | ||
328 | fn infer_project_associated_type() { | ||
329 | check_infer( | ||
330 | r#" | ||
331 | trait Iterable { | ||
332 | type Item; | ||
333 | } | ||
334 | struct S; | ||
335 | impl Iterable for S { type Item = u32; } | ||
336 | fn test<T: Iterable>() { | ||
337 | let x: <S as Iterable>::Item = 1; | ||
338 | let y: <T as Iterable>::Item = no_matter; | ||
339 | let z: T::Item = no_matter; | ||
340 | let a: <T>::Item = no_matter; | ||
341 | } | ||
342 | "#, | ||
343 | expect![[r#" | ||
344 | 108..261 '{ ...ter; }': () | ||
345 | 118..119 'x': u32 | ||
346 | 145..146 '1': u32 | ||
347 | 156..157 'y': Iterable::Item<T> | ||
348 | 183..192 'no_matter': Iterable::Item<T> | ||
349 | 202..203 'z': Iterable::Item<T> | ||
350 | 215..224 'no_matter': Iterable::Item<T> | ||
351 | 234..235 'a': Iterable::Item<T> | ||
352 | 249..258 'no_matter': Iterable::Item<T> | ||
353 | "#]], | ||
354 | ); | ||
355 | } | ||
356 | |||
357 | #[test] | ||
358 | fn infer_return_associated_type() { | ||
359 | check_infer( | ||
360 | r#" | ||
361 | trait Iterable { | ||
362 | type Item; | ||
363 | } | ||
364 | struct S; | ||
365 | impl Iterable for S { type Item = u32; } | ||
366 | fn foo1<T: Iterable>(t: T) -> T::Item {} | ||
367 | fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {} | ||
368 | fn foo3<T: Iterable>(t: T) -> <T>::Item {} | ||
369 | fn test() { | ||
370 | let x = foo1(S); | ||
371 | let y = foo2(S); | ||
372 | let z = foo3(S); | ||
373 | } | ||
374 | "#, | ||
375 | expect![[r#" | ||
376 | 106..107 't': T | ||
377 | 123..125 '{}': () | ||
378 | 147..148 't': T | ||
379 | 178..180 '{}': () | ||
380 | 202..203 't': T | ||
381 | 221..223 '{}': () | ||
382 | 234..300 '{ ...(S); }': () | ||
383 | 244..245 'x': u32 | ||
384 | 248..252 'foo1': fn foo1<S>(S) -> <S as Iterable>::Item | ||
385 | 248..255 'foo1(S)': u32 | ||
386 | 253..254 'S': S | ||
387 | 265..266 'y': u32 | ||
388 | 269..273 'foo2': fn foo2<S>(S) -> <S as Iterable>::Item | ||
389 | 269..276 'foo2(S)': u32 | ||
390 | 274..275 'S': S | ||
391 | 286..287 'z': u32 | ||
392 | 290..294 'foo3': fn foo3<S>(S) -> <S as Iterable>::Item | ||
393 | 290..297 'foo3(S)': u32 | ||
394 | 295..296 'S': S | ||
395 | "#]], | ||
396 | ); | ||
397 | } | ||
398 | |||
399 | #[test] | ||
400 | fn infer_associated_type_bound() { | ||
401 | check_infer( | ||
402 | r#" | ||
403 | trait Iterable { | ||
404 | type Item; | ||
405 | } | ||
406 | fn test<T: Iterable<Item=u32>>() { | ||
407 | let y: T::Item = unknown; | ||
408 | } | ||
409 | "#, | ||
410 | expect![[r#" | ||
411 | 67..100 '{ ...own; }': () | ||
412 | 77..78 'y': u32 | ||
413 | 90..97 'unknown': u32 | ||
414 | "#]], | ||
415 | ); | ||
416 | } | ||
417 | |||
418 | #[test] | ||
419 | fn infer_const_body() { | ||
420 | check_infer( | ||
421 | r#" | ||
422 | const A: u32 = 1 + 1; | ||
423 | static B: u64 = { let x = 1; x }; | ||
424 | "#, | ||
425 | expect![[r#" | ||
426 | 15..16 '1': u32 | ||
427 | 15..20 '1 + 1': u32 | ||
428 | 19..20 '1': u32 | ||
429 | 38..54 '{ let ...1; x }': u64 | ||
430 | 44..45 'x': u64 | ||
431 | 48..49 '1': u64 | ||
432 | 51..52 'x': u64 | ||
433 | "#]], | ||
434 | ); | ||
435 | } | ||
436 | |||
437 | #[test] | ||
438 | fn tuple_struct_fields() { | ||
439 | check_infer( | ||
440 | r#" | ||
441 | struct S(i32, u64); | ||
442 | fn test() -> u64 { | ||
443 | let a = S(4, 6); | ||
444 | let b = a.0; | ||
445 | a.1 | ||
446 | } | ||
447 | "#, | ||
448 | expect![[r#" | ||
449 | 37..86 '{ ... a.1 }': u64 | ||
450 | 47..48 'a': S | ||
451 | 51..52 'S': S(i32, u64) -> S | ||
452 | 51..58 'S(4, 6)': S | ||
453 | 53..54 '4': i32 | ||
454 | 56..57 '6': u64 | ||
455 | 68..69 'b': i32 | ||
456 | 72..73 'a': S | ||
457 | 72..75 'a.0': i32 | ||
458 | 81..82 'a': S | ||
459 | 81..84 'a.1': u64 | ||
460 | "#]], | ||
461 | ); | ||
462 | } | ||
463 | |||
464 | #[test] | ||
465 | fn tuple_struct_with_fn() { | ||
466 | check_infer( | ||
467 | r#" | ||
468 | struct S(fn(u32) -> u64); | ||
469 | fn test() -> u64 { | ||
470 | let a = S(|i| 2*i); | ||
471 | let b = a.0(4); | ||
472 | a.0(2) | ||
473 | } | ||
474 | "#, | ||
475 | expect![[r#" | ||
476 | 43..101 '{ ...0(2) }': u64 | ||
477 | 53..54 'a': S | ||
478 | 57..58 'S': S(fn(u32) -> u64) -> S | ||
479 | 57..67 'S(|i| 2*i)': S | ||
480 | 59..66 '|i| 2*i': |u32| -> u64 | ||
481 | 60..61 'i': u32 | ||
482 | 63..64 '2': u32 | ||
483 | 63..66 '2*i': u32 | ||
484 | 65..66 'i': u32 | ||
485 | 77..78 'b': u64 | ||
486 | 81..82 'a': S | ||
487 | 81..84 'a.0': fn(u32) -> u64 | ||
488 | 81..87 'a.0(4)': u64 | ||
489 | 85..86 '4': u32 | ||
490 | 93..94 'a': S | ||
491 | 93..96 'a.0': fn(u32) -> u64 | ||
492 | 93..99 'a.0(2)': u64 | ||
493 | 97..98 '2': u32 | ||
494 | "#]], | ||
495 | ); | ||
496 | } | ||
497 | |||
498 | #[test] | ||
499 | fn indexing_arrays() { | ||
500 | check_infer( | ||
501 | "fn main() { &mut [9][2]; }", | ||
502 | expect![[r#" | ||
503 | 10..26 '{ &mut...[2]; }': () | ||
504 | 12..23 '&mut [9][2]': &mut {unknown} | ||
505 | 17..20 '[9]': [i32; _] | ||
506 | 17..23 '[9][2]': {unknown} | ||
507 | 18..19 '9': i32 | ||
508 | 21..22 '2': i32 | ||
509 | "#]], | ||
510 | ) | ||
511 | } | ||
512 | |||
513 | #[test] | ||
514 | fn infer_ops_index() { | ||
515 | check_types( | ||
516 | r#" | ||
517 | //- /main.rs crate:main deps:std | ||
518 | struct Bar; | ||
519 | struct Foo; | ||
520 | |||
521 | impl std::ops::Index<u32> for Bar { | ||
522 | type Output = Foo; | ||
523 | } | ||
524 | |||
525 | fn test() { | ||
526 | let a = Bar; | ||
527 | let b = a[1u32]; | ||
528 | b; | ||
529 | } //^ Foo | ||
530 | |||
531 | //- /std.rs crate:std | ||
532 | #[prelude_import] use ops::*; | ||
533 | mod ops { | ||
534 | #[lang = "index"] | ||
535 | pub trait Index<Idx> { | ||
536 | type Output; | ||
537 | } | ||
538 | } | ||
539 | "#, | ||
540 | ); | ||
541 | } | ||
542 | |||
543 | #[test] | ||
544 | fn infer_ops_index_int() { | ||
545 | check_types( | ||
546 | r#" | ||
547 | //- /main.rs crate:main deps:std | ||
548 | struct Bar; | ||
549 | struct Foo; | ||
550 | |||
551 | impl std::ops::Index<u32> for Bar { | ||
552 | type Output = Foo; | ||
553 | } | ||
554 | |||
555 | struct Range; | ||
556 | impl std::ops::Index<Range> for Bar { | ||
557 | type Output = Bar; | ||
558 | } | ||
559 | |||
560 | fn test() { | ||
561 | let a = Bar; | ||
562 | let b = a[1]; | ||
563 | b; | ||
564 | //^ Foo | ||
565 | } | ||
566 | |||
567 | //- /std.rs crate:std | ||
568 | #[prelude_import] use ops::*; | ||
569 | mod ops { | ||
570 | #[lang = "index"] | ||
571 | pub trait Index<Idx> { | ||
572 | type Output; | ||
573 | } | ||
574 | } | ||
575 | "#, | ||
576 | ); | ||
577 | } | ||
578 | |||
579 | #[test] | ||
580 | fn infer_ops_index_autoderef() { | ||
581 | check_types( | ||
582 | r#" | ||
583 | //- /main.rs crate:main deps:std | ||
584 | fn test() { | ||
585 | let a = &[1u32, 2, 3]; | ||
586 | let b = a[1u32]; | ||
587 | b; | ||
588 | } //^ u32 | ||
589 | |||
590 | //- /std.rs crate:std | ||
591 | impl<T> ops::Index<u32> for [T] { | ||
592 | type Output = T; | ||
593 | } | ||
594 | |||
595 | #[prelude_import] use ops::*; | ||
596 | mod ops { | ||
597 | #[lang = "index"] | ||
598 | pub trait Index<Idx> { | ||
599 | type Output; | ||
600 | } | ||
601 | } | ||
602 | "#, | ||
603 | ); | ||
604 | } | ||
605 | |||
606 | #[test] | ||
607 | fn deref_trait() { | ||
608 | check_types( | ||
609 | r#" | ||
610 | #[lang = "deref"] | ||
611 | trait Deref { | ||
612 | type Target; | ||
613 | fn deref(&self) -> &Self::Target; | ||
614 | } | ||
615 | |||
616 | struct Arc<T>; | ||
617 | impl<T> Deref for Arc<T> { | ||
618 | type Target = T; | ||
619 | } | ||
620 | |||
621 | struct S; | ||
622 | impl S { | ||
623 | fn foo(&self) -> u128 {} | ||
624 | } | ||
625 | |||
626 | fn test(s: Arc<S>) { | ||
627 | (*s, s.foo()); | ||
628 | } //^ (S, u128) | ||
629 | "#, | ||
630 | ); | ||
631 | } | ||
632 | |||
633 | #[test] | ||
634 | fn deref_trait_with_inference_var() { | ||
635 | check_types( | ||
636 | r#" | ||
637 | //- /main.rs | ||
638 | #[lang = "deref"] | ||
639 | trait Deref { | ||
640 | type Target; | ||
641 | fn deref(&self) -> &Self::Target; | ||
642 | } | ||
643 | |||
644 | struct Arc<T>; | ||
645 | fn new_arc<T>() -> Arc<T> {} | ||
646 | impl<T> Deref for Arc<T> { | ||
647 | type Target = T; | ||
648 | } | ||
649 | |||
650 | struct S; | ||
651 | fn foo(a: Arc<S>) {} | ||
652 | |||
653 | fn test() { | ||
654 | let a = new_arc(); | ||
655 | let b = (*a); | ||
656 | //^ S | ||
657 | foo(a); | ||
658 | } | ||
659 | "#, | ||
660 | ); | ||
661 | } | ||
662 | |||
663 | #[test] | ||
664 | fn deref_trait_infinite_recursion() { | ||
665 | check_types( | ||
666 | r#" | ||
667 | #[lang = "deref"] | ||
668 | trait Deref { | ||
669 | type Target; | ||
670 | fn deref(&self) -> &Self::Target; | ||
671 | } | ||
672 | |||
673 | struct S; | ||
674 | |||
675 | impl Deref for S { | ||
676 | type Target = S; | ||
677 | } | ||
678 | |||
679 | fn test(s: S) { | ||
680 | s.foo(); | ||
681 | } //^ {unknown} | ||
682 | "#, | ||
683 | ); | ||
684 | } | ||
685 | |||
686 | #[test] | ||
687 | fn deref_trait_with_question_mark_size() { | ||
688 | check_types( | ||
689 | r#" | ||
690 | #[lang = "deref"] | ||
691 | trait Deref { | ||
692 | type Target; | ||
693 | fn deref(&self) -> &Self::Target; | ||
694 | } | ||
695 | |||
696 | struct Arc<T>; | ||
697 | impl<T> Deref for Arc<T> { | ||
698 | type Target = T; | ||
699 | } | ||
700 | |||
701 | struct S; | ||
702 | impl S { | ||
703 | fn foo(&self) -> u128 {} | ||
704 | } | ||
705 | |||
706 | fn test(s: Arc<S>) { | ||
707 | (*s, s.foo()); | ||
708 | } //^ (S, u128) | ||
709 | "#, | ||
710 | ); | ||
711 | } | ||
712 | |||
713 | #[test] | ||
714 | fn obligation_from_function_clause() { | ||
715 | check_types( | ||
716 | r#" | ||
717 | struct S; | ||
718 | |||
719 | trait Trait<T> {} | ||
720 | impl Trait<u32> for S {} | ||
721 | |||
722 | fn foo<T: Trait<U>, U>(t: T) -> U {} | ||
723 | |||
724 | fn test(s: S) { | ||
725 | (foo(s)); | ||
726 | } //^ u32 | ||
727 | "#, | ||
728 | ); | ||
729 | } | ||
730 | |||
731 | #[test] | ||
732 | fn obligation_from_method_clause() { | ||
733 | check_types( | ||
734 | r#" | ||
735 | //- /main.rs | ||
736 | struct S; | ||
737 | |||
738 | trait Trait<T> {} | ||
739 | impl Trait<isize> for S {} | ||
740 | |||
741 | struct O; | ||
742 | impl O { | ||
743 | fn foo<T: Trait<U>, U>(&self, t: T) -> U {} | ||
744 | } | ||
745 | |||
746 | fn test() { | ||
747 | O.foo(S); | ||
748 | } //^ isize | ||
749 | "#, | ||
750 | ); | ||
751 | } | ||
752 | |||
753 | #[test] | ||
754 | fn obligation_from_self_method_clause() { | ||
755 | check_types( | ||
756 | r#" | ||
757 | struct S; | ||
758 | |||
759 | trait Trait<T> {} | ||
760 | impl Trait<i64> for S {} | ||
761 | |||
762 | impl S { | ||
763 | fn foo<U>(&self) -> U where Self: Trait<U> {} | ||
764 | } | ||
765 | |||
766 | fn test() { | ||
767 | S.foo(); | ||
768 | } //^ i64 | ||
769 | "#, | ||
770 | ); | ||
771 | } | ||
772 | |||
773 | #[test] | ||
774 | fn obligation_from_impl_clause() { | ||
775 | check_types( | ||
776 | r#" | ||
777 | struct S; | ||
778 | |||
779 | trait Trait<T> {} | ||
780 | impl Trait<&str> for S {} | ||
781 | |||
782 | struct O<T>; | ||
783 | impl<U, T: Trait<U>> O<T> { | ||
784 | fn foo(&self) -> U {} | ||
785 | } | ||
786 | |||
787 | fn test(o: O<S>) { | ||
788 | o.foo(); | ||
789 | } //^ &str | ||
790 | "#, | ||
791 | ); | ||
792 | } | ||
793 | |||
794 | #[test] | ||
795 | fn generic_param_env_1() { | ||
796 | check_types( | ||
797 | r#" | ||
798 | trait Clone {} | ||
799 | trait Trait { fn foo(self) -> u128; } | ||
800 | struct S; | ||
801 | impl Clone for S {} | ||
802 | impl<T> Trait for T where T: Clone {} | ||
803 | fn test<T: Clone>(t: T) { t.foo(); } | ||
804 | //^ u128 | ||
805 | "#, | ||
806 | ); | ||
807 | } | ||
808 | |||
809 | #[test] | ||
810 | fn generic_param_env_1_not_met() { | ||
811 | check_types( | ||
812 | r#" | ||
813 | //- /main.rs | ||
814 | trait Clone {} | ||
815 | trait Trait { fn foo(self) -> u128; } | ||
816 | struct S; | ||
817 | impl Clone for S {} | ||
818 | impl<T> Trait for T where T: Clone {} | ||
819 | fn test<T>(t: T) { t.foo(); } | ||
820 | //^ {unknown} | ||
821 | "#, | ||
822 | ); | ||
823 | } | ||
824 | |||
825 | #[test] | ||
826 | fn generic_param_env_2() { | ||
827 | check_types( | ||
828 | r#" | ||
829 | trait Trait { fn foo(self) -> u128; } | ||
830 | struct S; | ||
831 | impl Trait for S {} | ||
832 | fn test<T: Trait>(t: T) { t.foo(); } | ||
833 | //^ u128 | ||
834 | "#, | ||
835 | ); | ||
836 | } | ||
837 | |||
838 | #[test] | ||
839 | fn generic_param_env_2_not_met() { | ||
840 | check_types( | ||
841 | r#" | ||
842 | trait Trait { fn foo(self) -> u128; } | ||
843 | struct S; | ||
844 | impl Trait for S {} | ||
845 | fn test<T>(t: T) { t.foo(); } | ||
846 | //^ {unknown} | ||
847 | "#, | ||
848 | ); | ||
849 | } | ||
850 | |||
851 | #[test] | ||
852 | fn generic_param_env_deref() { | ||
853 | check_types( | ||
854 | r#" | ||
855 | #[lang = "deref"] | ||
856 | trait Deref { | ||
857 | type Target; | ||
858 | } | ||
859 | trait Trait {} | ||
860 | impl<T> Deref for T where T: Trait { | ||
861 | type Target = i128; | ||
862 | } | ||
863 | fn test<T: Trait>(t: T) { (*t); } | ||
864 | //^ i128 | ||
865 | "#, | ||
866 | ); | ||
867 | } | ||
868 | |||
869 | #[test] | ||
870 | fn associated_type_placeholder() { | ||
871 | // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. | ||
872 | check_types( | ||
873 | r#" | ||
874 | pub trait ApplyL { | ||
875 | type Out; | ||
876 | } | ||
877 | |||
878 | pub struct RefMutL<T>; | ||
879 | |||
880 | impl<T> ApplyL for RefMutL<T> { | ||
881 | type Out = <T as ApplyL>::Out; | ||
882 | } | ||
883 | |||
884 | fn test<T: ApplyL>() { | ||
885 | let y: <RefMutL<T> as ApplyL>::Out = no_matter; | ||
886 | y; | ||
887 | } //^ ApplyL::Out<T> | ||
888 | "#, | ||
889 | ); | ||
890 | } | ||
891 | |||
892 | #[test] | ||
893 | fn associated_type_placeholder_2() { | ||
894 | check_types( | ||
895 | r#" | ||
896 | pub trait ApplyL { | ||
897 | type Out; | ||
898 | } | ||
899 | fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out; | ||
900 | |||
901 | fn test<T: ApplyL>(t: T) { | ||
902 | let y = foo(t); | ||
903 | y; | ||
904 | } //^ ApplyL::Out<T> | ||
905 | "#, | ||
906 | ); | ||
907 | } | ||
908 | |||
909 | #[test] | ||
910 | fn argument_impl_trait() { | ||
911 | check_infer_with_mismatches( | ||
912 | r#" | ||
913 | trait Trait<T> { | ||
914 | fn foo(&self) -> T; | ||
915 | fn foo2(&self) -> i64; | ||
916 | } | ||
917 | fn bar(x: impl Trait<u16>) {} | ||
918 | struct S<T>(T); | ||
919 | impl<T> Trait<T> for S<T> {} | ||
920 | |||
921 | fn test(x: impl Trait<u64>, y: &impl Trait<u32>) { | ||
922 | x; | ||
923 | y; | ||
924 | let z = S(1); | ||
925 | bar(z); | ||
926 | x.foo(); | ||
927 | y.foo(); | ||
928 | z.foo(); | ||
929 | x.foo2(); | ||
930 | y.foo2(); | ||
931 | z.foo2(); | ||
932 | } | ||
933 | "#, | ||
934 | expect![[r#" | ||
935 | 29..33 'self': &Self | ||
936 | 54..58 'self': &Self | ||
937 | 77..78 'x': impl Trait<u16> | ||
938 | 97..99 '{}': () | ||
939 | 154..155 'x': impl Trait<u64> | ||
940 | 174..175 'y': &impl Trait<u32> | ||
941 | 195..323 '{ ...2(); }': () | ||
942 | 201..202 'x': impl Trait<u64> | ||
943 | 208..209 'y': &impl Trait<u32> | ||
944 | 219..220 'z': S<u16> | ||
945 | 223..224 'S': S<u16>(u16) -> S<u16> | ||
946 | 223..227 'S(1)': S<u16> | ||
947 | 225..226 '1': u16 | ||
948 | 233..236 'bar': fn bar(S<u16>) | ||
949 | 233..239 'bar(z)': () | ||
950 | 237..238 'z': S<u16> | ||
951 | 245..246 'x': impl Trait<u64> | ||
952 | 245..252 'x.foo()': u64 | ||
953 | 258..259 'y': &impl Trait<u32> | ||
954 | 258..265 'y.foo()': u32 | ||
955 | 271..272 'z': S<u16> | ||
956 | 271..278 'z.foo()': u16 | ||
957 | 284..285 'x': impl Trait<u64> | ||
958 | 284..292 'x.foo2()': i64 | ||
959 | 298..299 'y': &impl Trait<u32> | ||
960 | 298..306 'y.foo2()': i64 | ||
961 | 312..313 'z': S<u16> | ||
962 | 312..320 'z.foo2()': i64 | ||
963 | "#]], | ||
964 | ); | ||
965 | } | ||
966 | |||
967 | #[test] | ||
968 | fn argument_impl_trait_type_args_1() { | ||
969 | check_infer_with_mismatches( | ||
970 | r#" | ||
971 | trait Trait {} | ||
972 | trait Foo { | ||
973 | // this function has an implicit Self param, an explicit type param, | ||
974 | // and an implicit impl Trait param! | ||
975 | fn bar<T>(x: impl Trait) -> T { loop {} } | ||
976 | } | ||
977 | fn foo<T>(x: impl Trait) -> T { loop {} } | ||
978 | struct S; | ||
979 | impl Trait for S {} | ||
980 | struct F; | ||
981 | impl Foo for F {} | ||
982 | |||
983 | fn test() { | ||
984 | Foo::bar(S); | ||
985 | <F as Foo>::bar(S); | ||
986 | F::bar(S); | ||
987 | Foo::bar::<u32>(S); | ||
988 | <F as Foo>::bar::<u32>(S); | ||
989 | |||
990 | foo(S); | ||
991 | foo::<u32>(S); | ||
992 | foo::<u32, i32>(S); // we should ignore the extraneous i32 | ||
993 | } | ||
994 | "#, | ||
995 | expect![[r#" | ||
996 | 155..156 'x': impl Trait | ||
997 | 175..186 '{ loop {} }': T | ||
998 | 177..184 'loop {}': ! | ||
999 | 182..184 '{}': () | ||
1000 | 199..200 'x': impl Trait | ||
1001 | 219..230 '{ loop {} }': T | ||
1002 | 221..228 'loop {}': ! | ||
1003 | 226..228 '{}': () | ||
1004 | 300..509 '{ ... i32 }': () | ||
1005 | 306..314 'Foo::bar': fn bar<{unknown}, {unknown}>(S) -> {unknown} | ||
1006 | 306..317 'Foo::bar(S)': {unknown} | ||
1007 | 315..316 'S': S | ||
1008 | 323..338 '<F as Foo>::bar': fn bar<F, {unknown}>(S) -> {unknown} | ||
1009 | 323..341 '<F as ...bar(S)': {unknown} | ||
1010 | 339..340 'S': S | ||
1011 | 347..353 'F::bar': fn bar<F, {unknown}>(S) -> {unknown} | ||
1012 | 347..356 'F::bar(S)': {unknown} | ||
1013 | 354..355 'S': S | ||
1014 | 362..377 'Foo::bar::<u32>': fn bar<{unknown}, u32>(S) -> u32 | ||
1015 | 362..380 'Foo::b...32>(S)': u32 | ||
1016 | 378..379 'S': S | ||
1017 | 386..408 '<F as ...:<u32>': fn bar<F, u32>(S) -> u32 | ||
1018 | 386..411 '<F as ...32>(S)': u32 | ||
1019 | 409..410 'S': S | ||
1020 | 418..421 'foo': fn foo<{unknown}>(S) -> {unknown} | ||
1021 | 418..424 'foo(S)': {unknown} | ||
1022 | 422..423 'S': S | ||
1023 | 430..440 'foo::<u32>': fn foo<u32>(S) -> u32 | ||
1024 | 430..443 'foo::<u32>(S)': u32 | ||
1025 | 441..442 'S': S | ||
1026 | 449..464 'foo::<u32, i32>': fn foo<u32>(S) -> u32 | ||
1027 | 449..467 'foo::<...32>(S)': u32 | ||
1028 | 465..466 'S': S | ||
1029 | "#]], | ||
1030 | ); | ||
1031 | } | ||
1032 | |||
1033 | #[test] | ||
1034 | fn argument_impl_trait_type_args_2() { | ||
1035 | check_infer_with_mismatches( | ||
1036 | r#" | ||
1037 | trait Trait {} | ||
1038 | struct S; | ||
1039 | impl Trait for S {} | ||
1040 | struct F<T>; | ||
1041 | impl<T> F<T> { | ||
1042 | fn foo<U>(self, x: impl Trait) -> (T, U) { loop {} } | ||
1043 | } | ||
1044 | |||
1045 | fn test() { | ||
1046 | F.foo(S); | ||
1047 | F::<u32>.foo(S); | ||
1048 | F::<u32>.foo::<i32>(S); | ||
1049 | F::<u32>.foo::<i32, u32>(S); // extraneous argument should be ignored | ||
1050 | } | ||
1051 | "#, | ||
1052 | expect![[r#" | ||
1053 | 87..91 'self': F<T> | ||
1054 | 93..94 'x': impl Trait | ||
1055 | 118..129 '{ loop {} }': (T, U) | ||
1056 | 120..127 'loop {}': ! | ||
1057 | 125..127 '{}': () | ||
1058 | 143..283 '{ ...ored }': () | ||
1059 | 149..150 'F': F<{unknown}> | ||
1060 | 149..157 'F.foo(S)': ({unknown}, {unknown}) | ||
1061 | 155..156 'S': S | ||
1062 | 163..171 'F::<u32>': F<u32> | ||
1063 | 163..178 'F::<u32>.foo(S)': (u32, {unknown}) | ||
1064 | 176..177 'S': S | ||
1065 | 184..192 'F::<u32>': F<u32> | ||
1066 | 184..206 'F::<u3...32>(S)': (u32, i32) | ||
1067 | 204..205 'S': S | ||
1068 | 212..220 'F::<u32>': F<u32> | ||
1069 | 212..239 'F::<u3...32>(S)': (u32, i32) | ||
1070 | 237..238 'S': S | ||
1071 | "#]], | ||
1072 | ); | ||
1073 | } | ||
1074 | |||
1075 | #[test] | ||
1076 | fn argument_impl_trait_to_fn_pointer() { | ||
1077 | check_infer_with_mismatches( | ||
1078 | r#" | ||
1079 | trait Trait {} | ||
1080 | fn foo(x: impl Trait) { loop {} } | ||
1081 | struct S; | ||
1082 | impl Trait for S {} | ||
1083 | |||
1084 | fn test() { | ||
1085 | let f: fn(S) -> () = foo; | ||
1086 | } | ||
1087 | "#, | ||
1088 | expect![[r#" | ||
1089 | 22..23 'x': impl Trait | ||
1090 | 37..48 '{ loop {} }': () | ||
1091 | 39..46 'loop {}': ! | ||
1092 | 44..46 '{}': () | ||
1093 | 90..123 '{ ...foo; }': () | ||
1094 | 100..101 'f': fn(S) | ||
1095 | 117..120 'foo': fn foo(S) | ||
1096 | "#]], | ||
1097 | ); | ||
1098 | } | ||
1099 | |||
1100 | #[test] | ||
1101 | fn impl_trait() { | ||
1102 | check_infer( | ||
1103 | r#" | ||
1104 | trait Trait<T> { | ||
1105 | fn foo(&self) -> T; | ||
1106 | fn foo2(&self) -> i64; | ||
1107 | } | ||
1108 | fn bar() -> impl Trait<u64> {} | ||
1109 | |||
1110 | fn test(x: impl Trait<u64>, y: &impl Trait<u64>) { | ||
1111 | x; | ||
1112 | y; | ||
1113 | let z = bar(); | ||
1114 | x.foo(); | ||
1115 | y.foo(); | ||
1116 | z.foo(); | ||
1117 | x.foo2(); | ||
1118 | y.foo2(); | ||
1119 | z.foo2(); | ||
1120 | } | ||
1121 | "#, | ||
1122 | expect![[r#" | ||
1123 | 29..33 'self': &Self | ||
1124 | 54..58 'self': &Self | ||
1125 | 98..100 '{}': () | ||
1126 | 110..111 'x': impl Trait<u64> | ||
1127 | 130..131 'y': &impl Trait<u64> | ||
1128 | 151..268 '{ ...2(); }': () | ||
1129 | 157..158 'x': impl Trait<u64> | ||
1130 | 164..165 'y': &impl Trait<u64> | ||
1131 | 175..176 'z': impl Trait<u64> | ||
1132 | 179..182 'bar': fn bar() -> impl Trait<u64> | ||
1133 | 179..184 'bar()': impl Trait<u64> | ||
1134 | 190..191 'x': impl Trait<u64> | ||
1135 | 190..197 'x.foo()': u64 | ||
1136 | 203..204 'y': &impl Trait<u64> | ||
1137 | 203..210 'y.foo()': u64 | ||
1138 | 216..217 'z': impl Trait<u64> | ||
1139 | 216..223 'z.foo()': u64 | ||
1140 | 229..230 'x': impl Trait<u64> | ||
1141 | 229..237 'x.foo2()': i64 | ||
1142 | 243..244 'y': &impl Trait<u64> | ||
1143 | 243..251 'y.foo2()': i64 | ||
1144 | 257..258 'z': impl Trait<u64> | ||
1145 | 257..265 'z.foo2()': i64 | ||
1146 | "#]], | ||
1147 | ); | ||
1148 | } | ||
1149 | |||
1150 | #[test] | ||
1151 | fn simple_return_pos_impl_trait() { | ||
1152 | mark::check!(lower_rpit); | ||
1153 | check_infer( | ||
1154 | r#" | ||
1155 | trait Trait<T> { | ||
1156 | fn foo(&self) -> T; | ||
1157 | } | ||
1158 | fn bar() -> impl Trait<u64> { loop {} } | ||
1159 | |||
1160 | fn test() { | ||
1161 | let a = bar(); | ||
1162 | a.foo(); | ||
1163 | } | ||
1164 | "#, | ||
1165 | expect![[r#" | ||
1166 | 29..33 'self': &Self | ||
1167 | 71..82 '{ loop {} }': ! | ||
1168 | 73..80 'loop {}': ! | ||
1169 | 78..80 '{}': () | ||
1170 | 94..129 '{ ...o(); }': () | ||
1171 | 104..105 'a': impl Trait<u64> | ||
1172 | 108..111 'bar': fn bar() -> impl Trait<u64> | ||
1173 | 108..113 'bar()': impl Trait<u64> | ||
1174 | 119..120 'a': impl Trait<u64> | ||
1175 | 119..126 'a.foo()': u64 | ||
1176 | "#]], | ||
1177 | ); | ||
1178 | } | ||
1179 | |||
1180 | #[test] | ||
1181 | fn more_return_pos_impl_trait() { | ||
1182 | check_infer( | ||
1183 | r#" | ||
1184 | trait Iterator { | ||
1185 | type Item; | ||
1186 | fn next(&mut self) -> Self::Item; | ||
1187 | } | ||
1188 | trait Trait<T> { | ||
1189 | fn foo(&self) -> T; | ||
1190 | } | ||
1191 | fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} } | ||
1192 | fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} } | ||
1193 | |||
1194 | fn test() { | ||
1195 | let (a, b) = bar(); | ||
1196 | a.next().foo(); | ||
1197 | b.foo(); | ||
1198 | let (c, d) = baz(1u128); | ||
1199 | c.next().foo(); | ||
1200 | d.foo(); | ||
1201 | } | ||
1202 | "#, | ||
1203 | expect![[r#" | ||
1204 | 49..53 'self': &mut Self | ||
1205 | 101..105 'self': &Self | ||
1206 | 184..195 '{ loop {} }': ({unknown}, {unknown}) | ||
1207 | 186..193 'loop {}': ! | ||
1208 | 191..193 '{}': () | ||
1209 | 206..207 't': T | ||
1210 | 268..279 '{ loop {} }': ({unknown}, {unknown}) | ||
1211 | 270..277 'loop {}': ! | ||
1212 | 275..277 '{}': () | ||
1213 | 291..413 '{ ...o(); }': () | ||
1214 | 301..307 '(a, b)': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) | ||
1215 | 302..303 'a': impl Iterator<Item = impl Trait<u32>> | ||
1216 | 305..306 'b': impl Trait<u64> | ||
1217 | 310..313 'bar': fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) | ||
1218 | 310..315 'bar()': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) | ||
1219 | 321..322 'a': impl Iterator<Item = impl Trait<u32>> | ||
1220 | 321..329 'a.next()': impl Trait<u32> | ||
1221 | 321..335 'a.next().foo()': u32 | ||
1222 | 341..342 'b': impl Trait<u64> | ||
1223 | 341..348 'b.foo()': u64 | ||
1224 | 358..364 '(c, d)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) | ||
1225 | 359..360 'c': impl Iterator<Item = impl Trait<u128>> | ||
1226 | 362..363 'd': impl Trait<u128> | ||
1227 | 367..370 'baz': fn baz<u128>(u128) -> (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) | ||
1228 | 367..377 'baz(1u128)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) | ||
1229 | 371..376 '1u128': u128 | ||
1230 | 383..384 'c': impl Iterator<Item = impl Trait<u128>> | ||
1231 | 383..391 'c.next()': impl Trait<u128> | ||
1232 | 383..397 'c.next().foo()': u128 | ||
1233 | 403..404 'd': impl Trait<u128> | ||
1234 | 403..410 'd.foo()': u128 | ||
1235 | "#]], | ||
1236 | ); | ||
1237 | } | ||
1238 | |||
1239 | #[test] | ||
1240 | fn dyn_trait() { | ||
1241 | check_infer( | ||
1242 | r#" | ||
1243 | trait Trait<T> { | ||
1244 | fn foo(&self) -> T; | ||
1245 | fn foo2(&self) -> i64; | ||
1246 | } | ||
1247 | fn bar() -> dyn Trait<u64> {} | ||
1248 | |||
1249 | fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) { | ||
1250 | x; | ||
1251 | y; | ||
1252 | let z = bar(); | ||
1253 | x.foo(); | ||
1254 | y.foo(); | ||
1255 | z.foo(); | ||
1256 | x.foo2(); | ||
1257 | y.foo2(); | ||
1258 | z.foo2(); | ||
1259 | } | ||
1260 | "#, | ||
1261 | expect![[r#" | ||
1262 | 29..33 'self': &Self | ||
1263 | 54..58 'self': &Self | ||
1264 | 97..99 '{}': () | ||
1265 | 109..110 'x': dyn Trait<u64> | ||
1266 | 128..129 'y': &dyn Trait<u64> | ||
1267 | 148..265 '{ ...2(); }': () | ||
1268 | 154..155 'x': dyn Trait<u64> | ||
1269 | 161..162 'y': &dyn Trait<u64> | ||
1270 | 172..173 'z': dyn Trait<u64> | ||
1271 | 176..179 'bar': fn bar() -> dyn Trait<u64> | ||
1272 | 176..181 'bar()': dyn Trait<u64> | ||
1273 | 187..188 'x': dyn Trait<u64> | ||
1274 | 187..194 'x.foo()': u64 | ||
1275 | 200..201 'y': &dyn Trait<u64> | ||
1276 | 200..207 'y.foo()': u64 | ||
1277 | 213..214 'z': dyn Trait<u64> | ||
1278 | 213..220 'z.foo()': u64 | ||
1279 | 226..227 'x': dyn Trait<u64> | ||
1280 | 226..234 'x.foo2()': i64 | ||
1281 | 240..241 'y': &dyn Trait<u64> | ||
1282 | 240..248 'y.foo2()': i64 | ||
1283 | 254..255 'z': dyn Trait<u64> | ||
1284 | 254..262 'z.foo2()': i64 | ||
1285 | "#]], | ||
1286 | ); | ||
1287 | } | ||
1288 | |||
1289 | #[test] | ||
1290 | fn dyn_trait_in_impl() { | ||
1291 | check_infer( | ||
1292 | r#" | ||
1293 | trait Trait<T, U> { | ||
1294 | fn foo(&self) -> (T, U); | ||
1295 | } | ||
1296 | struct S<T, U> {} | ||
1297 | impl<T, U> S<T, U> { | ||
1298 | fn bar(&self) -> &dyn Trait<T, U> { loop {} } | ||
1299 | } | ||
1300 | trait Trait2<T, U> { | ||
1301 | fn baz(&self) -> (T, U); | ||
1302 | } | ||
1303 | impl<T, U> Trait2<T, U> for dyn Trait<T, U> { } | ||
1304 | |||
1305 | fn test(s: S<u32, i32>) { | ||
1306 | s.bar().baz(); | ||
1307 | } | ||
1308 | "#, | ||
1309 | expect![[r#" | ||
1310 | 32..36 'self': &Self | ||
1311 | 102..106 'self': &S<T, U> | ||
1312 | 128..139 '{ loop {} }': &dyn Trait<T, U> | ||
1313 | 130..137 'loop {}': ! | ||
1314 | 135..137 '{}': () | ||
1315 | 175..179 'self': &Self | ||
1316 | 251..252 's': S<u32, i32> | ||
1317 | 267..289 '{ ...z(); }': () | ||
1318 | 273..274 's': S<u32, i32> | ||
1319 | 273..280 's.bar()': &dyn Trait<u32, i32> | ||
1320 | 273..286 's.bar().baz()': (u32, i32) | ||
1321 | "#]], | ||
1322 | ); | ||
1323 | } | ||
1324 | |||
1325 | #[test] | ||
1326 | fn dyn_trait_bare() { | ||
1327 | check_infer( | ||
1328 | r#" | ||
1329 | trait Trait { | ||
1330 | fn foo(&self) -> u64; | ||
1331 | } | ||
1332 | fn bar() -> Trait {} | ||
1333 | |||
1334 | fn test(x: Trait, y: &Trait) -> u64 { | ||
1335 | x; | ||
1336 | y; | ||
1337 | let z = bar(); | ||
1338 | x.foo(); | ||
1339 | y.foo(); | ||
1340 | z.foo(); | ||
1341 | } | ||
1342 | "#, | ||
1343 | expect![[r#" | ||
1344 | 26..30 'self': &Self | ||
1345 | 60..62 '{}': () | ||
1346 | 72..73 'x': dyn Trait | ||
1347 | 82..83 'y': &dyn Trait | ||
1348 | 100..175 '{ ...o(); }': () | ||
1349 | 106..107 'x': dyn Trait | ||
1350 | 113..114 'y': &dyn Trait | ||
1351 | 124..125 'z': dyn Trait | ||
1352 | 128..131 'bar': fn bar() -> dyn Trait | ||
1353 | 128..133 'bar()': dyn Trait | ||
1354 | 139..140 'x': dyn Trait | ||
1355 | 139..146 'x.foo()': u64 | ||
1356 | 152..153 'y': &dyn Trait | ||
1357 | 152..159 'y.foo()': u64 | ||
1358 | 165..166 'z': dyn Trait | ||
1359 | 165..172 'z.foo()': u64 | ||
1360 | "#]], | ||
1361 | ); | ||
1362 | } | ||
1363 | |||
1364 | #[test] | ||
1365 | fn weird_bounds() { | ||
1366 | check_infer( | ||
1367 | r#" | ||
1368 | trait Trait {} | ||
1369 | fn test(a: impl Trait + 'lifetime, b: impl 'lifetime, c: impl (Trait), d: impl ('lifetime), e: impl ?Sized, f: impl Trait + ?Sized) {} | ||
1370 | "#, | ||
1371 | expect![[r#" | ||
1372 | 23..24 'a': impl Trait + {error} | ||
1373 | 50..51 'b': impl {error} | ||
1374 | 69..70 'c': impl Trait | ||
1375 | 86..87 'd': impl {error} | ||
1376 | 107..108 'e': impl {error} | ||
1377 | 123..124 'f': impl Trait + {error} | ||
1378 | 147..149 '{}': () | ||
1379 | "#]], | ||
1380 | ); | ||
1381 | } | ||
1382 | |||
1383 | #[test] | ||
1384 | #[ignore] | ||
1385 | fn error_bound_chalk() { | ||
1386 | check_types( | ||
1387 | r#" | ||
1388 | trait Trait { | ||
1389 | fn foo(&self) -> u32 {} | ||
1390 | } | ||
1391 | |||
1392 | fn test(x: (impl Trait + UnknownTrait)) { | ||
1393 | x.foo(); | ||
1394 | } //^ u32 | ||
1395 | "#, | ||
1396 | ); | ||
1397 | } | ||
1398 | |||
1399 | #[test] | ||
1400 | fn assoc_type_bindings() { | ||
1401 | check_infer( | ||
1402 | r#" | ||
1403 | trait Trait { | ||
1404 | type Type; | ||
1405 | } | ||
1406 | |||
1407 | fn get<T: Trait>(t: T) -> <T as Trait>::Type {} | ||
1408 | fn get2<U, T: Trait<Type = U>>(t: T) -> U {} | ||
1409 | fn set<T: Trait<Type = u64>>(t: T) -> T {t} | ||
1410 | |||
1411 | struct S<T>; | ||
1412 | impl<T> Trait for S<T> { type Type = T; } | ||
1413 | |||
1414 | fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { | ||
1415 | get(x); | ||
1416 | get2(x); | ||
1417 | get(y); | ||
1418 | get2(y); | ||
1419 | get(set(S)); | ||
1420 | get2(set(S)); | ||
1421 | get2(S::<str>); | ||
1422 | } | ||
1423 | "#, | ||
1424 | expect![[r#" | ||
1425 | 49..50 't': T | ||
1426 | 77..79 '{}': () | ||
1427 | 111..112 't': T | ||
1428 | 122..124 '{}': () | ||
1429 | 154..155 't': T | ||
1430 | 165..168 '{t}': T | ||
1431 | 166..167 't': T | ||
1432 | 256..257 'x': T | ||
1433 | 262..263 'y': impl Trait<Type = i64> | ||
1434 | 289..397 '{ ...r>); }': () | ||
1435 | 295..298 'get': fn get<T>(T) -> <T as Trait>::Type | ||
1436 | 295..301 'get(x)': u32 | ||
1437 | 299..300 'x': T | ||
1438 | 307..311 'get2': fn get2<u32, T>(T) -> u32 | ||
1439 | 307..314 'get2(x)': u32 | ||
1440 | 312..313 'x': T | ||
1441 | 320..323 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type | ||
1442 | 320..326 'get(y)': i64 | ||
1443 | 324..325 'y': impl Trait<Type = i64> | ||
1444 | 332..336 'get2': fn get2<i64, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> i64 | ||
1445 | 332..339 'get2(y)': i64 | ||
1446 | 337..338 'y': impl Trait<Type = i64> | ||
1447 | 345..348 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type | ||
1448 | 345..356 'get(set(S))': u64 | ||
1449 | 349..352 'set': fn set<S<u64>>(S<u64>) -> S<u64> | ||
1450 | 349..355 'set(S)': S<u64> | ||
1451 | 353..354 'S': S<u64> | ||
1452 | 362..366 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64 | ||
1453 | 362..374 'get2(set(S))': u64 | ||
1454 | 367..370 'set': fn set<S<u64>>(S<u64>) -> S<u64> | ||
1455 | 367..373 'set(S)': S<u64> | ||
1456 | 371..372 'S': S<u64> | ||
1457 | 380..384 'get2': fn get2<str, S<str>>(S<str>) -> str | ||
1458 | 380..394 'get2(S::<str>)': str | ||
1459 | 385..393 'S::<str>': S<str> | ||
1460 | "#]], | ||
1461 | ); | ||
1462 | } | ||
1463 | |||
1464 | #[test] | ||
1465 | fn impl_trait_assoc_binding_projection_bug() { | ||
1466 | check_types( | ||
1467 | r#" | ||
1468 | //- /main.rs crate:main deps:std | ||
1469 | pub trait Language { | ||
1470 | type Kind; | ||
1471 | } | ||
1472 | pub enum RustLanguage {} | ||
1473 | impl Language for RustLanguage { | ||
1474 | type Kind = SyntaxKind; | ||
1475 | } | ||
1476 | struct SyntaxNode<L> {} | ||
1477 | fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {} | ||
1478 | |||
1479 | trait Clone { | ||
1480 | fn clone(&self) -> Self; | ||
1481 | } | ||
1482 | |||
1483 | fn api_walkthrough() { | ||
1484 | for node in foo() { | ||
1485 | node.clone(); | ||
1486 | } //^ {unknown} | ||
1487 | } | ||
1488 | |||
1489 | //- /std.rs crate:std | ||
1490 | #[prelude_import] use iter::*; | ||
1491 | mod iter { | ||
1492 | trait IntoIterator { | ||
1493 | type Item; | ||
1494 | } | ||
1495 | trait Iterator { | ||
1496 | type Item; | ||
1497 | } | ||
1498 | impl<T: Iterator> IntoIterator for T { | ||
1499 | type Item = <T as Iterator>::Item; | ||
1500 | } | ||
1501 | } | ||
1502 | "#, | ||
1503 | ); | ||
1504 | } | ||
1505 | |||
1506 | #[test] | ||
1507 | fn projection_eq_within_chalk() { | ||
1508 | check_infer( | ||
1509 | r#" | ||
1510 | trait Trait1 { | ||
1511 | type Type; | ||
1512 | } | ||
1513 | trait Trait2<T> { | ||
1514 | fn foo(self) -> T; | ||
1515 | } | ||
1516 | impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {} | ||
1517 | |||
1518 | fn test<T: Trait1<Type = u32>>(x: T) { | ||
1519 | x.foo(); | ||
1520 | } | ||
1521 | "#, | ||
1522 | expect![[r#" | ||
1523 | 61..65 'self': Self | ||
1524 | 163..164 'x': T | ||
1525 | 169..185 '{ ...o(); }': () | ||
1526 | 175..176 'x': T | ||
1527 | 175..182 'x.foo()': u32 | ||
1528 | "#]], | ||
1529 | ); | ||
1530 | } | ||
1531 | |||
1532 | #[test] | ||
1533 | fn where_clause_trait_in_scope_for_method_resolution() { | ||
1534 | check_types( | ||
1535 | r#" | ||
1536 | mod foo { | ||
1537 | trait Trait { | ||
1538 | fn foo(&self) -> u32 {} | ||
1539 | } | ||
1540 | } | ||
1541 | |||
1542 | fn test<T: foo::Trait>(x: T) { | ||
1543 | x.foo(); | ||
1544 | } //^ u32 | ||
1545 | "#, | ||
1546 | ); | ||
1547 | } | ||
1548 | |||
1549 | #[test] | ||
1550 | fn super_trait_method_resolution() { | ||
1551 | check_infer( | ||
1552 | r#" | ||
1553 | mod foo { | ||
1554 | trait SuperTrait { | ||
1555 | fn foo(&self) -> u32 {} | ||
1556 | } | ||
1557 | } | ||
1558 | trait Trait1: foo::SuperTrait {} | ||
1559 | trait Trait2 where Self: foo::SuperTrait {} | ||
1560 | |||
1561 | fn test<T: Trait1, U: Trait2>(x: T, y: U) { | ||
1562 | x.foo(); | ||
1563 | y.foo(); | ||
1564 | } | ||
1565 | "#, | ||
1566 | expect![[r#" | ||
1567 | 49..53 'self': &Self | ||
1568 | 62..64 '{}': () | ||
1569 | 181..182 'x': T | ||
1570 | 187..188 'y': U | ||
1571 | 193..222 '{ ...o(); }': () | ||
1572 | 199..200 'x': T | ||
1573 | 199..206 'x.foo()': u32 | ||
1574 | 212..213 'y': U | ||
1575 | 212..219 'y.foo()': u32 | ||
1576 | "#]], | ||
1577 | ); | ||
1578 | } | ||
1579 | |||
1580 | #[test] | ||
1581 | fn super_trait_impl_trait_method_resolution() { | ||
1582 | check_infer( | ||
1583 | r#" | ||
1584 | mod foo { | ||
1585 | trait SuperTrait { | ||
1586 | fn foo(&self) -> u32 {} | ||
1587 | } | ||
1588 | } | ||
1589 | trait Trait1: foo::SuperTrait {} | ||
1590 | |||
1591 | fn test(x: &impl Trait1) { | ||
1592 | x.foo(); | ||
1593 | } | ||
1594 | "#, | ||
1595 | expect![[r#" | ||
1596 | 49..53 'self': &Self | ||
1597 | 62..64 '{}': () | ||
1598 | 115..116 'x': &impl Trait1 | ||
1599 | 132..148 '{ ...o(); }': () | ||
1600 | 138..139 'x': &impl Trait1 | ||
1601 | 138..145 'x.foo()': u32 | ||
1602 | "#]], | ||
1603 | ); | ||
1604 | } | ||
1605 | |||
1606 | #[test] | ||
1607 | fn super_trait_cycle() { | ||
1608 | // This just needs to not crash | ||
1609 | check_infer( | ||
1610 | r#" | ||
1611 | trait A: B {} | ||
1612 | trait B: A {} | ||
1613 | |||
1614 | fn test<T: A>(x: T) { | ||
1615 | x.foo(); | ||
1616 | } | ||
1617 | "#, | ||
1618 | expect![[r#" | ||
1619 | 43..44 'x': T | ||
1620 | 49..65 '{ ...o(); }': () | ||
1621 | 55..56 'x': T | ||
1622 | 55..62 'x.foo()': {unknown} | ||
1623 | "#]], | ||
1624 | ); | ||
1625 | } | ||
1626 | |||
1627 | #[test] | ||
1628 | fn super_trait_assoc_type_bounds() { | ||
1629 | check_infer( | ||
1630 | r#" | ||
1631 | trait SuperTrait { type Type; } | ||
1632 | trait Trait where Self: SuperTrait {} | ||
1633 | |||
1634 | fn get2<U, T: Trait<Type = U>>(t: T) -> U {} | ||
1635 | fn set<T: Trait<Type = u64>>(t: T) -> T {t} | ||
1636 | |||
1637 | struct S<T>; | ||
1638 | impl<T> SuperTrait for S<T> { type Type = T; } | ||
1639 | impl<T> Trait for S<T> {} | ||
1640 | |||
1641 | fn test() { | ||
1642 | get2(set(S)); | ||
1643 | } | ||
1644 | "#, | ||
1645 | expect![[r#" | ||
1646 | 102..103 't': T | ||
1647 | 113..115 '{}': () | ||
1648 | 145..146 't': T | ||
1649 | 156..159 '{t}': T | ||
1650 | 157..158 't': T | ||
1651 | 258..279 '{ ...S)); }': () | ||
1652 | 264..268 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64 | ||
1653 | 264..276 'get2(set(S))': u64 | ||
1654 | 269..272 'set': fn set<S<u64>>(S<u64>) -> S<u64> | ||
1655 | 269..275 'set(S)': S<u64> | ||
1656 | 273..274 'S': S<u64> | ||
1657 | "#]], | ||
1658 | ); | ||
1659 | } | ||
1660 | |||
1661 | #[test] | ||
1662 | fn fn_trait() { | ||
1663 | check_infer( | ||
1664 | r#" | ||
1665 | trait FnOnce<Args> { | ||
1666 | type Output; | ||
1667 | |||
1668 | fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output; | ||
1669 | } | ||
1670 | |||
1671 | fn test<F: FnOnce(u32, u64) -> u128>(f: F) { | ||
1672 | f.call_once((1, 2)); | ||
1673 | } | ||
1674 | "#, | ||
1675 | expect![[r#" | ||
1676 | 56..60 'self': Self | ||
1677 | 62..66 'args': Args | ||
1678 | 149..150 'f': F | ||
1679 | 155..183 '{ ...2)); }': () | ||
1680 | 161..162 'f': F | ||
1681 | 161..180 'f.call...1, 2))': u128 | ||
1682 | 173..179 '(1, 2)': (u32, u64) | ||
1683 | 174..175 '1': u32 | ||
1684 | 177..178 '2': u64 | ||
1685 | "#]], | ||
1686 | ); | ||
1687 | } | ||
1688 | |||
1689 | #[test] | ||
1690 | fn fn_ptr_and_item() { | ||
1691 | check_infer( | ||
1692 | r#" | ||
1693 | #[lang="fn_once"] | ||
1694 | trait FnOnce<Args> { | ||
1695 | type Output; | ||
1696 | |||
1697 | fn call_once(self, args: Args) -> Self::Output; | ||
1698 | } | ||
1699 | |||
1700 | trait Foo<T> { | ||
1701 | fn foo(&self) -> T; | ||
1702 | } | ||
1703 | |||
1704 | struct Bar<T>(T); | ||
1705 | |||
1706 | impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> { | ||
1707 | fn foo(&self) -> (A1, R) {} | ||
1708 | } | ||
1709 | |||
1710 | enum Opt<T> { None, Some(T) } | ||
1711 | impl<T> Opt<T> { | ||
1712 | fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> {} | ||
1713 | } | ||
1714 | |||
1715 | fn test() { | ||
1716 | let bar: Bar<fn(u8) -> u32>; | ||
1717 | bar.foo(); | ||
1718 | |||
1719 | let opt: Opt<u8>; | ||
1720 | let f: fn(u8) -> u32; | ||
1721 | opt.map(f); | ||
1722 | } | ||
1723 | "#, | ||
1724 | expect![[r#" | ||
1725 | 74..78 'self': Self | ||
1726 | 80..84 'args': Args | ||
1727 | 139..143 'self': &Self | ||
1728 | 243..247 'self': &Bar<F> | ||
1729 | 260..262 '{}': () | ||
1730 | 346..350 'self': Opt<T> | ||
1731 | 352..353 'f': F | ||
1732 | 368..370 '{}': () | ||
1733 | 384..500 '{ ...(f); }': () | ||
1734 | 394..397 'bar': Bar<fn(u8) -> u32> | ||
1735 | 423..426 'bar': Bar<fn(u8) -> u32> | ||
1736 | 423..432 'bar.foo()': (u8, u32) | ||
1737 | 443..446 'opt': Opt<u8> | ||
1738 | 465..466 'f': fn(u8) -> u32 | ||
1739 | 487..490 'opt': Opt<u8> | ||
1740 | 487..497 'opt.map(f)': Opt<u32> | ||
1741 | 495..496 'f': fn(u8) -> u32 | ||
1742 | "#]], | ||
1743 | ); | ||
1744 | } | ||
1745 | |||
1746 | #[test] | ||
1747 | fn fn_trait_deref_with_ty_default() { | ||
1748 | check_infer( | ||
1749 | r#" | ||
1750 | #[lang = "deref"] | ||
1751 | trait Deref { | ||
1752 | type Target; | ||
1753 | |||
1754 | fn deref(&self) -> &Self::Target; | ||
1755 | } | ||
1756 | |||
1757 | #[lang="fn_once"] | ||
1758 | trait FnOnce<Args> { | ||
1759 | type Output; | ||
1760 | |||
1761 | fn call_once(self, args: Args) -> Self::Output; | ||
1762 | } | ||
1763 | |||
1764 | struct Foo; | ||
1765 | |||
1766 | impl Foo { | ||
1767 | fn foo(&self) -> usize {} | ||
1768 | } | ||
1769 | |||
1770 | struct Lazy<T, F = fn() -> T>(F); | ||
1771 | |||
1772 | impl<T, F> Lazy<T, F> { | ||
1773 | pub fn new(f: F) -> Lazy<T, F> {} | ||
1774 | } | ||
1775 | |||
1776 | impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> { | ||
1777 | type Target = T; | ||
1778 | } | ||
1779 | |||
1780 | fn test() { | ||
1781 | let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo); | ||
1782 | let r1 = lazy1.foo(); | ||
1783 | |||
1784 | fn make_foo_fn() -> Foo {} | ||
1785 | let make_foo_fn_ptr: fn() -> Foo = make_foo_fn; | ||
1786 | let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr); | ||
1787 | let r2 = lazy2.foo(); | ||
1788 | } | ||
1789 | "#, | ||
1790 | expect![[r#" | ||
1791 | 64..68 'self': &Self | ||
1792 | 165..169 'self': Self | ||
1793 | 171..175 'args': Args | ||
1794 | 239..243 'self': &Foo | ||
1795 | 254..256 '{}': () | ||
1796 | 334..335 'f': F | ||
1797 | 354..356 '{}': () | ||
1798 | 443..689 '{ ...o(); }': () | ||
1799 | 453..458 'lazy1': Lazy<Foo, || -> Foo> | ||
1800 | 475..484 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo> | ||
1801 | 475..492 'Lazy::...| Foo)': Lazy<Foo, || -> Foo> | ||
1802 | 485..491 '|| Foo': || -> Foo | ||
1803 | 488..491 'Foo': Foo | ||
1804 | 502..504 'r1': usize | ||
1805 | 507..512 'lazy1': Lazy<Foo, || -> Foo> | ||
1806 | 507..518 'lazy1.foo()': usize | ||
1807 | 560..575 'make_foo_fn_ptr': fn() -> Foo | ||
1808 | 591..602 'make_foo_fn': fn make_foo_fn() -> Foo | ||
1809 | 612..617 'lazy2': Lazy<Foo, fn() -> Foo> | ||
1810 | 634..643 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo> | ||
1811 | 634..660 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo> | ||
1812 | 644..659 'make_foo_fn_ptr': fn() -> Foo | ||
1813 | 670..672 'r2': usize | ||
1814 | 675..680 'lazy2': Lazy<Foo, fn() -> Foo> | ||
1815 | 675..686 'lazy2.foo()': usize | ||
1816 | 549..551 '{}': () | ||
1817 | "#]], | ||
1818 | ); | ||
1819 | } | ||
1820 | |||
1821 | #[test] | ||
1822 | fn closure_1() { | ||
1823 | check_infer( | ||
1824 | r#" | ||
1825 | #[lang = "fn_once"] | ||
1826 | trait FnOnce<Args> { | ||
1827 | type Output; | ||
1828 | } | ||
1829 | |||
1830 | enum Option<T> { Some(T), None } | ||
1831 | impl<T> Option<T> { | ||
1832 | fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {} | ||
1833 | } | ||
1834 | |||
1835 | fn test() { | ||
1836 | let x = Option::Some(1u32); | ||
1837 | x.map(|v| v + 1); | ||
1838 | x.map(|_v| 1u64); | ||
1839 | let y: Option<i64> = x.map(|_v| 1); | ||
1840 | } | ||
1841 | "#, | ||
1842 | expect![[r#" | ||
1843 | 147..151 'self': Option<T> | ||
1844 | 153..154 'f': F | ||
1845 | 172..174 '{}': () | ||
1846 | 188..307 '{ ... 1); }': () | ||
1847 | 198..199 'x': Option<u32> | ||
1848 | 202..214 'Option::Some': Some<u32>(u32) -> Option<u32> | ||
1849 | 202..220 'Option...(1u32)': Option<u32> | ||
1850 | 215..219 '1u32': u32 | ||
1851 | 226..227 'x': Option<u32> | ||
1852 | 226..242 'x.map(...v + 1)': Option<u32> | ||
1853 | 232..241 '|v| v + 1': |u32| -> u32 | ||
1854 | 233..234 'v': u32 | ||
1855 | 236..237 'v': u32 | ||
1856 | 236..241 'v + 1': u32 | ||
1857 | 240..241 '1': u32 | ||
1858 | 248..249 'x': Option<u32> | ||
1859 | 248..264 'x.map(... 1u64)': Option<u64> | ||
1860 | 254..263 '|_v| 1u64': |u32| -> u64 | ||
1861 | 255..257 '_v': u32 | ||
1862 | 259..263 '1u64': u64 | ||
1863 | 274..275 'y': Option<i64> | ||
1864 | 291..292 'x': Option<u32> | ||
1865 | 291..304 'x.map(|_v| 1)': Option<i64> | ||
1866 | 297..303 '|_v| 1': |u32| -> i64 | ||
1867 | 298..300 '_v': u32 | ||
1868 | 302..303 '1': i64 | ||
1869 | "#]], | ||
1870 | ); | ||
1871 | } | ||
1872 | |||
1873 | #[test] | ||
1874 | fn closure_2() { | ||
1875 | check_infer( | ||
1876 | r#" | ||
1877 | trait FnOnce<Args> { | ||
1878 | type Output; | ||
1879 | } | ||
1880 | |||
1881 | fn test<F: FnOnce(u32) -> u64>(f: F) { | ||
1882 | f(1); | ||
1883 | let g = |v| v + 1; | ||
1884 | g(1u64); | ||
1885 | let h = |v| 1u128 + v; | ||
1886 | } | ||
1887 | "#, | ||
1888 | expect![[r#" | ||
1889 | 72..73 'f': F | ||
1890 | 78..154 '{ ...+ v; }': () | ||
1891 | 84..85 'f': F | ||
1892 | 84..88 'f(1)': {unknown} | ||
1893 | 86..87 '1': i32 | ||
1894 | 98..99 'g': |u64| -> i32 | ||
1895 | 102..111 '|v| v + 1': |u64| -> i32 | ||
1896 | 103..104 'v': u64 | ||
1897 | 106..107 'v': u64 | ||
1898 | 106..111 'v + 1': i32 | ||
1899 | 110..111 '1': i32 | ||
1900 | 117..118 'g': |u64| -> i32 | ||
1901 | 117..124 'g(1u64)': i32 | ||
1902 | 119..123 '1u64': u64 | ||
1903 | 134..135 'h': |u128| -> u128 | ||
1904 | 138..151 '|v| 1u128 + v': |u128| -> u128 | ||
1905 | 139..140 'v': u128 | ||
1906 | 142..147 '1u128': u128 | ||
1907 | 142..151 '1u128 + v': u128 | ||
1908 | 150..151 'v': u128 | ||
1909 | "#]], | ||
1910 | ); | ||
1911 | } | ||
1912 | |||
1913 | #[test] | ||
1914 | fn closure_as_argument_inference_order() { | ||
1915 | check_infer( | ||
1916 | r#" | ||
1917 | #[lang = "fn_once"] | ||
1918 | trait FnOnce<Args> { | ||
1919 | type Output; | ||
1920 | } | ||
1921 | |||
1922 | fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {} | ||
1923 | fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {} | ||
1924 | |||
1925 | struct S; | ||
1926 | impl S { | ||
1927 | fn method(self) -> u64; | ||
1928 | |||
1929 | fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {} | ||
1930 | fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {} | ||
1931 | } | ||
1932 | |||
1933 | fn test() { | ||
1934 | let x1 = foo1(S, |s| s.method()); | ||
1935 | let x2 = foo2(|s| s.method(), S); | ||
1936 | let x3 = S.foo1(S, |s| s.method()); | ||
1937 | let x4 = S.foo2(|s| s.method(), S); | ||
1938 | } | ||
1939 | "#, | ||
1940 | expect![[r#" | ||
1941 | 94..95 'x': T | ||
1942 | 100..101 'f': F | ||
1943 | 111..113 '{}': () | ||
1944 | 147..148 'f': F | ||
1945 | 153..154 'x': T | ||
1946 | 164..166 '{}': () | ||
1947 | 201..205 'self': S | ||
1948 | 253..257 'self': S | ||
1949 | 259..260 'x': T | ||
1950 | 265..266 'f': F | ||
1951 | 276..278 '{}': () | ||
1952 | 316..320 'self': S | ||
1953 | 322..323 'f': F | ||
1954 | 328..329 'x': T | ||
1955 | 339..341 '{}': () | ||
1956 | 355..514 '{ ... S); }': () | ||
1957 | 365..367 'x1': u64 | ||
1958 | 370..374 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64 | ||
1959 | 370..393 'foo1(S...hod())': u64 | ||
1960 | 375..376 'S': S | ||
1961 | 378..392 '|s| s.method()': |S| -> u64 | ||
1962 | 379..380 's': S | ||
1963 | 382..383 's': S | ||
1964 | 382..392 's.method()': u64 | ||
1965 | 403..405 'x2': u64 | ||
1966 | 408..412 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64 | ||
1967 | 408..431 'foo2(|...(), S)': u64 | ||
1968 | 413..427 '|s| s.method()': |S| -> u64 | ||
1969 | 414..415 's': S | ||
1970 | 417..418 's': S | ||
1971 | 417..427 's.method()': u64 | ||
1972 | 429..430 'S': S | ||
1973 | 441..443 'x3': u64 | ||
1974 | 446..447 'S': S | ||
1975 | 446..471 'S.foo1...hod())': u64 | ||
1976 | 453..454 'S': S | ||
1977 | 456..470 '|s| s.method()': |S| -> u64 | ||
1978 | 457..458 's': S | ||
1979 | 460..461 's': S | ||
1980 | 460..470 's.method()': u64 | ||
1981 | 481..483 'x4': u64 | ||
1982 | 486..487 'S': S | ||
1983 | 486..511 'S.foo2...(), S)': u64 | ||
1984 | 493..507 '|s| s.method()': |S| -> u64 | ||
1985 | 494..495 's': S | ||
1986 | 497..498 's': S | ||
1987 | 497..507 's.method()': u64 | ||
1988 | 509..510 'S': S | ||
1989 | "#]], | ||
1990 | ); | ||
1991 | } | ||
1992 | |||
1993 | #[test] | ||
1994 | fn fn_item_fn_trait() { | ||
1995 | check_types( | ||
1996 | r#" | ||
1997 | #[lang = "fn_once"] | ||
1998 | trait FnOnce<Args> { | ||
1999 | type Output; | ||
2000 | } | ||
2001 | |||
2002 | struct S; | ||
2003 | |||
2004 | fn foo() -> S {} | ||
2005 | |||
2006 | fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() } | ||
2007 | |||
2008 | fn test() { | ||
2009 | takes_closure(foo); | ||
2010 | } //^^^^^^^^^^^^^^^^^^ S | ||
2011 | "#, | ||
2012 | ); | ||
2013 | } | ||
2014 | |||
2015 | #[test] | ||
2016 | fn unselected_projection_in_trait_env_1() { | ||
2017 | check_types( | ||
2018 | r#" | ||
2019 | //- /main.rs | ||
2020 | trait Trait { | ||
2021 | type Item; | ||
2022 | } | ||
2023 | |||
2024 | trait Trait2 { | ||
2025 | fn foo(&self) -> u32; | ||
2026 | } | ||
2027 | |||
2028 | fn test<T: Trait>() where T::Item: Trait2 { | ||
2029 | let x: T::Item = no_matter; | ||
2030 | x.foo(); | ||
2031 | } //^ u32 | ||
2032 | "#, | ||
2033 | ); | ||
2034 | } | ||
2035 | |||
2036 | #[test] | ||
2037 | fn unselected_projection_in_trait_env_2() { | ||
2038 | check_types( | ||
2039 | r#" | ||
2040 | trait Trait<T> { | ||
2041 | type Item; | ||
2042 | } | ||
2043 | |||
2044 | trait Trait2 { | ||
2045 | fn foo(&self) -> u32; | ||
2046 | } | ||
2047 | |||
2048 | fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { | ||
2049 | let x: T::Item = no_matter; | ||
2050 | x.foo(); | ||
2051 | } //^ u32 | ||
2052 | "#, | ||
2053 | ); | ||
2054 | } | ||
2055 | |||
2056 | #[test] | ||
2057 | fn unselected_projection_on_impl_self() { | ||
2058 | check_infer( | ||
2059 | r#" | ||
2060 | //- /main.rs | ||
2061 | trait Trait { | ||
2062 | type Item; | ||
2063 | |||
2064 | fn f(&self, x: Self::Item); | ||
2065 | } | ||
2066 | |||
2067 | struct S; | ||
2068 | |||
2069 | impl Trait for S { | ||
2070 | type Item = u32; | ||
2071 | fn f(&self, x: Self::Item) { let y = x; } | ||
2072 | } | ||
2073 | |||
2074 | struct S2; | ||
2075 | |||
2076 | impl Trait for S2 { | ||
2077 | type Item = i32; | ||
2078 | fn f(&self, x: <Self>::Item) { let y = x; } | ||
2079 | } | ||
2080 | "#, | ||
2081 | expect![[r#" | ||
2082 | 40..44 'self': &Self | ||
2083 | 46..47 'x': Trait::Item<Self> | ||
2084 | 126..130 'self': &S | ||
2085 | 132..133 'x': u32 | ||
2086 | 147..161 '{ let y = x; }': () | ||
2087 | 153..154 'y': u32 | ||
2088 | 157..158 'x': u32 | ||
2089 | 228..232 'self': &S2 | ||
2090 | 234..235 'x': i32 | ||
2091 | 251..265 '{ let y = x; }': () | ||
2092 | 257..258 'y': i32 | ||
2093 | 261..262 'x': i32 | ||
2094 | "#]], | ||
2095 | ); | ||
2096 | } | ||
2097 | |||
2098 | #[test] | ||
2099 | fn unselected_projection_on_trait_self() { | ||
2100 | check_types( | ||
2101 | r#" | ||
2102 | trait Trait { | ||
2103 | type Item; | ||
2104 | |||
2105 | fn f(&self) -> Self::Item { loop {} } | ||
2106 | } | ||
2107 | |||
2108 | struct S; | ||
2109 | impl Trait for S { | ||
2110 | type Item = u32; | ||
2111 | } | ||
2112 | |||
2113 | fn test() { | ||
2114 | S.f(); | ||
2115 | } //^ u32 | ||
2116 | "#, | ||
2117 | ); | ||
2118 | } | ||
2119 | |||
2120 | #[test] | ||
2121 | fn unselected_projection_chalk_fold() { | ||
2122 | check_types( | ||
2123 | r#" | ||
2124 | trait Interner {} | ||
2125 | trait Fold<I: Interner, TI = I> { | ||
2126 | type Result; | ||
2127 | } | ||
2128 | |||
2129 | struct Ty<I: Interner> {} | ||
2130 | impl<I: Interner, TI: Interner> Fold<I, TI> for Ty<I> { | ||
2131 | type Result = Ty<TI>; | ||
2132 | } | ||
2133 | |||
2134 | fn fold<I: Interner, T>(interner: &I, t: T) -> T::Result | ||
2135 | where | ||
2136 | T: Fold<I, I>, | ||
2137 | { | ||
2138 | loop {} | ||
2139 | } | ||
2140 | |||
2141 | fn foo<I: Interner>(interner: &I, t: Ty<I>) { | ||
2142 | fold(interner, t); | ||
2143 | } //^ Ty<I> | ||
2144 | "#, | ||
2145 | ); | ||
2146 | } | ||
2147 | |||
2148 | #[test] | ||
2149 | fn trait_impl_self_ty() { | ||
2150 | check_types( | ||
2151 | r#" | ||
2152 | trait Trait<T> { | ||
2153 | fn foo(&self); | ||
2154 | } | ||
2155 | |||
2156 | struct S; | ||
2157 | |||
2158 | impl Trait<Self> for S {} | ||
2159 | |||
2160 | fn test() { | ||
2161 | S.foo(); | ||
2162 | } //^ () | ||
2163 | "#, | ||
2164 | ); | ||
2165 | } | ||
2166 | |||
2167 | #[test] | ||
2168 | fn trait_impl_self_ty_cycle() { | ||
2169 | check_types( | ||
2170 | r#" | ||
2171 | trait Trait { | ||
2172 | fn foo(&self); | ||
2173 | } | ||
2174 | |||
2175 | struct S<T>; | ||
2176 | |||
2177 | impl Trait for S<Self> {} | ||
2178 | |||
2179 | fn test() { | ||
2180 | S.foo(); | ||
2181 | } //^ {unknown} | ||
2182 | "#, | ||
2183 | ); | ||
2184 | } | ||
2185 | |||
2186 | #[test] | ||
2187 | fn unselected_projection_in_trait_env_cycle_1() { | ||
2188 | // this is a legitimate cycle | ||
2189 | check_types( | ||
2190 | r#" | ||
2191 | trait Trait { | ||
2192 | type Item; | ||
2193 | } | ||
2194 | |||
2195 | trait Trait2<T> {} | ||
2196 | |||
2197 | fn test<T: Trait>() where T: Trait2<T::Item> { | ||
2198 | let x: T::Item = no_matter; | ||
2199 | } //^ {unknown} | ||
2200 | "#, | ||
2201 | ); | ||
2202 | } | ||
2203 | |||
2204 | #[test] | ||
2205 | fn unselected_projection_in_trait_env_cycle_2() { | ||
2206 | // this is a legitimate cycle | ||
2207 | check_types( | ||
2208 | r#" | ||
2209 | //- /main.rs | ||
2210 | trait Trait<T> { | ||
2211 | type Item; | ||
2212 | } | ||
2213 | |||
2214 | fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | ||
2215 | let x: T::Item = no_matter; | ||
2216 | } //^ {unknown} | ||
2217 | "#, | ||
2218 | ); | ||
2219 | } | ||
2220 | |||
2221 | #[test] | ||
2222 | fn inline_assoc_type_bounds_1() { | ||
2223 | check_types( | ||
2224 | r#" | ||
2225 | trait Iterator { | ||
2226 | type Item; | ||
2227 | } | ||
2228 | trait OtherTrait<T> { | ||
2229 | fn foo(&self) -> T; | ||
2230 | } | ||
2231 | |||
2232 | // workaround for Chalk assoc type normalization problems | ||
2233 | pub struct S<T>; | ||
2234 | impl<T: Iterator> Iterator for S<T> { | ||
2235 | type Item = <T as Iterator>::Item; | ||
2236 | } | ||
2237 | |||
2238 | fn test<I: Iterator<Item: OtherTrait<u32>>>() { | ||
2239 | let x: <S<I> as Iterator>::Item; | ||
2240 | x.foo(); | ||
2241 | } //^ u32 | ||
2242 | "#, | ||
2243 | ); | ||
2244 | } | ||
2245 | |||
2246 | #[test] | ||
2247 | fn inline_assoc_type_bounds_2() { | ||
2248 | check_types( | ||
2249 | r#" | ||
2250 | trait Iterator { | ||
2251 | type Item; | ||
2252 | } | ||
2253 | |||
2254 | fn test<I: Iterator<Item: Iterator<Item = u32>>>() { | ||
2255 | let x: <<I as Iterator>::Item as Iterator>::Item; | ||
2256 | x; | ||
2257 | } //^ u32 | ||
2258 | "#, | ||
2259 | ); | ||
2260 | } | ||
2261 | |||
2262 | #[test] | ||
2263 | fn proc_macro_server_types() { | ||
2264 | check_infer( | ||
2265 | r#" | ||
2266 | macro_rules! with_api { | ||
2267 | ($S:ident, $self:ident, $m:ident) => { | ||
2268 | $m! { | ||
2269 | TokenStream { | ||
2270 | fn new() -> $S::TokenStream; | ||
2271 | }, | ||
2272 | Group { | ||
2273 | }, | ||
2274 | } | ||
2275 | }; | ||
2276 | } | ||
2277 | macro_rules! associated_item { | ||
2278 | (type TokenStream) => | ||
2279 | (type TokenStream: 'static;); | ||
2280 | (type Group) => | ||
2281 | (type Group: 'static;); | ||
2282 | ($($item:tt)*) => ($($item)*;) | ||
2283 | } | ||
2284 | macro_rules! declare_server_traits { | ||
2285 | ($($name:ident { | ||
2286 | $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* | ||
2287 | }),* $(,)?) => { | ||
2288 | pub trait Types { | ||
2289 | $(associated_item!(type $name);)* | ||
2290 | } | ||
2291 | |||
2292 | $(pub trait $name: Types { | ||
2293 | $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)* | ||
2294 | })* | ||
2295 | |||
2296 | pub trait Server: Types $(+ $name)* {} | ||
2297 | impl<S: Types $(+ $name)*> Server for S {} | ||
2298 | } | ||
2299 | } | ||
2300 | |||
2301 | with_api!(Self, self_, declare_server_traits); | ||
2302 | struct G {} | ||
2303 | struct T {} | ||
2304 | struct Rustc; | ||
2305 | impl Types for Rustc { | ||
2306 | type TokenStream = T; | ||
2307 | type Group = G; | ||
2308 | } | ||
2309 | |||
2310 | fn make<T>() -> T { loop {} } | ||
2311 | impl TokenStream for Rustc { | ||
2312 | fn new() -> Self::TokenStream { | ||
2313 | let group: Self::Group = make(); | ||
2314 | make() | ||
2315 | } | ||
2316 | } | ||
2317 | "#, | ||
2318 | expect![[r#" | ||
2319 | 1061..1072 '{ loop {} }': T | ||
2320 | 1063..1070 'loop {}': ! | ||
2321 | 1068..1070 '{}': () | ||
2322 | 1136..1199 '{ ... }': T | ||
2323 | 1150..1155 'group': G | ||
2324 | 1171..1175 'make': fn make<G>() -> G | ||
2325 | 1171..1177 'make()': G | ||
2326 | 1187..1191 'make': fn make<T>() -> T | ||
2327 | 1187..1193 'make()': T | ||
2328 | "#]], | ||
2329 | ); | ||
2330 | } | ||
2331 | |||
2332 | #[test] | ||
2333 | fn unify_impl_trait() { | ||
2334 | check_infer_with_mismatches( | ||
2335 | r#" | ||
2336 | trait Trait<T> {} | ||
2337 | |||
2338 | fn foo(x: impl Trait<u32>) { loop {} } | ||
2339 | fn bar<T>(x: impl Trait<T>) -> T { loop {} } | ||
2340 | |||
2341 | struct S<T>(T); | ||
2342 | impl<T> Trait<T> for S<T> {} | ||
2343 | |||
2344 | fn default<T>() -> T { loop {} } | ||
2345 | |||
2346 | fn test() -> impl Trait<i32> { | ||
2347 | let s1 = S(default()); | ||
2348 | foo(s1); | ||
2349 | let x: i32 = bar(S(default())); | ||
2350 | S(default()) | ||
2351 | } | ||
2352 | "#, | ||
2353 | expect![[r#" | ||
2354 | 26..27 'x': impl Trait<u32> | ||
2355 | 46..57 '{ loop {} }': () | ||
2356 | 48..55 'loop {}': ! | ||
2357 | 53..55 '{}': () | ||
2358 | 68..69 'x': impl Trait<T> | ||
2359 | 91..102 '{ loop {} }': T | ||
2360 | 93..100 'loop {}': ! | ||
2361 | 98..100 '{}': () | ||
2362 | 171..182 '{ loop {} }': T | ||
2363 | 173..180 'loop {}': ! | ||
2364 | 178..180 '{}': () | ||
2365 | 213..309 '{ ...t()) }': S<{unknown}> | ||
2366 | 223..225 's1': S<u32> | ||
2367 | 228..229 'S': S<u32>(u32) -> S<u32> | ||
2368 | 228..240 'S(default())': S<u32> | ||
2369 | 230..237 'default': fn default<u32>() -> u32 | ||
2370 | 230..239 'default()': u32 | ||
2371 | 246..249 'foo': fn foo(S<u32>) | ||
2372 | 246..253 'foo(s1)': () | ||
2373 | 250..252 's1': S<u32> | ||
2374 | 263..264 'x': i32 | ||
2375 | 272..275 'bar': fn bar<i32>(S<i32>) -> i32 | ||
2376 | 272..289 'bar(S(...lt()))': i32 | ||
2377 | 276..277 'S': S<i32>(i32) -> S<i32> | ||
2378 | 276..288 'S(default())': S<i32> | ||
2379 | 278..285 'default': fn default<i32>() -> i32 | ||
2380 | 278..287 'default()': i32 | ||
2381 | 295..296 'S': S<{unknown}>({unknown}) -> S<{unknown}> | ||
2382 | 295..307 'S(default())': S<{unknown}> | ||
2383 | 297..304 'default': fn default<{unknown}>() -> {unknown} | ||
2384 | 297..306 'default()': {unknown} | ||
2385 | "#]], | ||
2386 | ); | ||
2387 | } | ||
2388 | |||
2389 | #[test] | ||
2390 | fn assoc_types_from_bounds() { | ||
2391 | check_infer( | ||
2392 | r#" | ||
2393 | //- /main.rs | ||
2394 | #[lang = "fn_once"] | ||
2395 | trait FnOnce<Args> { | ||
2396 | type Output; | ||
2397 | } | ||
2398 | |||
2399 | trait T { | ||
2400 | type O; | ||
2401 | } | ||
2402 | |||
2403 | impl T for () { | ||
2404 | type O = (); | ||
2405 | } | ||
2406 | |||
2407 | fn f<X, F>(_v: F) | ||
2408 | where | ||
2409 | X: T, | ||
2410 | F: FnOnce(&X::O), | ||
2411 | { } | ||
2412 | |||
2413 | fn main() { | ||
2414 | f::<(), _>(|z| { z; }); | ||
2415 | } | ||
2416 | "#, | ||
2417 | expect![[r#" | ||
2418 | 133..135 '_v': F | ||
2419 | 178..181 '{ }': () | ||
2420 | 193..224 '{ ... }); }': () | ||
2421 | 199..209 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ()) | ||
2422 | 199..221 'f::<()... z; })': () | ||
2423 | 210..220 '|z| { z; }': |&()| -> () | ||
2424 | 211..212 'z': &() | ||
2425 | 214..220 '{ z; }': () | ||
2426 | 216..217 'z': &() | ||
2427 | "#]], | ||
2428 | ); | ||
2429 | } | ||
2430 | |||
2431 | #[test] | ||
2432 | fn associated_type_bound() { | ||
2433 | check_types( | ||
2434 | r#" | ||
2435 | pub trait Trait { | ||
2436 | type Item: OtherTrait<u32>; | ||
2437 | } | ||
2438 | pub trait OtherTrait<T> { | ||
2439 | fn foo(&self) -> T; | ||
2440 | } | ||
2441 | |||
2442 | // this is just a workaround for chalk#234 | ||
2443 | pub struct S<T>; | ||
2444 | impl<T: Trait> Trait for S<T> { | ||
2445 | type Item = <T as Trait>::Item; | ||
2446 | } | ||
2447 | |||
2448 | fn test<T: Trait>() { | ||
2449 | let y: <S<T> as Trait>::Item = no_matter; | ||
2450 | y.foo(); | ||
2451 | } //^ u32 | ||
2452 | "#, | ||
2453 | ); | ||
2454 | } | ||
2455 | |||
2456 | #[test] | ||
2457 | fn dyn_trait_through_chalk() { | ||
2458 | check_types( | ||
2459 | r#" | ||
2460 | struct Box<T> {} | ||
2461 | #[lang = "deref"] | ||
2462 | trait Deref { | ||
2463 | type Target; | ||
2464 | } | ||
2465 | impl<T> Deref for Box<T> { | ||
2466 | type Target = T; | ||
2467 | } | ||
2468 | trait Trait { | ||
2469 | fn foo(&self); | ||
2470 | } | ||
2471 | |||
2472 | fn test(x: Box<dyn Trait>) { | ||
2473 | x.foo(); | ||
2474 | } //^ () | ||
2475 | "#, | ||
2476 | ); | ||
2477 | } | ||
2478 | |||
2479 | #[test] | ||
2480 | fn string_to_owned() { | ||
2481 | check_types( | ||
2482 | r#" | ||
2483 | struct String {} | ||
2484 | pub trait ToOwned { | ||
2485 | type Owned; | ||
2486 | fn to_owned(&self) -> Self::Owned; | ||
2487 | } | ||
2488 | impl ToOwned for str { | ||
2489 | type Owned = String; | ||
2490 | } | ||
2491 | fn test() { | ||
2492 | "foo".to_owned(); | ||
2493 | } //^ String | ||
2494 | "#, | ||
2495 | ); | ||
2496 | } | ||
2497 | |||
2498 | #[test] | ||
2499 | fn iterator_chain() { | ||
2500 | check_infer( | ||
2501 | r#" | ||
2502 | //- /main.rs | ||
2503 | #[lang = "fn_once"] | ||
2504 | trait FnOnce<Args> { | ||
2505 | type Output; | ||
2506 | } | ||
2507 | #[lang = "fn_mut"] | ||
2508 | trait FnMut<Args>: FnOnce<Args> { } | ||
2509 | |||
2510 | enum Option<T> { Some(T), None } | ||
2511 | use Option::*; | ||
2512 | |||
2513 | pub trait Iterator { | ||
2514 | type Item; | ||
2515 | |||
2516 | fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F> | ||
2517 | where | ||
2518 | F: FnMut(Self::Item) -> Option<B>, | ||
2519 | { loop {} } | ||
2520 | |||
2521 | fn for_each<F>(self, f: F) | ||
2522 | where | ||
2523 | F: FnMut(Self::Item), | ||
2524 | { loop {} } | ||
2525 | } | ||
2526 | |||
2527 | pub trait IntoIterator { | ||
2528 | type Item; | ||
2529 | type IntoIter: Iterator<Item = Self::Item>; | ||
2530 | fn into_iter(self) -> Self::IntoIter; | ||
2531 | } | ||
2532 | |||
2533 | pub struct FilterMap<I, F> { } | ||
2534 | impl<B, I: Iterator, F> Iterator for FilterMap<I, F> | ||
2535 | where | ||
2536 | F: FnMut(I::Item) -> Option<B>, | ||
2537 | { | ||
2538 | type Item = B; | ||
2539 | } | ||
2540 | |||
2541 | #[stable(feature = "rust1", since = "1.0.0")] | ||
2542 | impl<I: Iterator> IntoIterator for I { | ||
2543 | type Item = I::Item; | ||
2544 | type IntoIter = I; | ||
2545 | |||
2546 | fn into_iter(self) -> I { | ||
2547 | self | ||
2548 | } | ||
2549 | } | ||
2550 | |||
2551 | struct Vec<T> {} | ||
2552 | impl<T> Vec<T> { | ||
2553 | fn new() -> Self { loop {} } | ||
2554 | } | ||
2555 | |||
2556 | impl<T> IntoIterator for Vec<T> { | ||
2557 | type Item = T; | ||
2558 | type IntoIter = IntoIter<T>; | ||
2559 | } | ||
2560 | |||
2561 | pub struct IntoIter<T> { } | ||
2562 | impl<T> Iterator for IntoIter<T> { | ||
2563 | type Item = T; | ||
2564 | } | ||
2565 | |||
2566 | fn main() { | ||
2567 | Vec::<i32>::new().into_iter() | ||
2568 | .filter_map(|x| if x > 0 { Some(x as u32) } else { None }) | ||
2569 | .for_each(|y| { y; }); | ||
2570 | } | ||
2571 | "#, | ||
2572 | expect![[r#" | ||
2573 | 226..230 'self': Self | ||
2574 | 232..233 'f': F | ||
2575 | 317..328 '{ loop {} }': FilterMap<Self, F> | ||
2576 | 319..326 'loop {}': ! | ||
2577 | 324..326 '{}': () | ||
2578 | 349..353 'self': Self | ||
2579 | 355..356 'f': F | ||
2580 | 405..416 '{ loop {} }': () | ||
2581 | 407..414 'loop {}': ! | ||
2582 | 412..414 '{}': () | ||
2583 | 525..529 'self': Self | ||
2584 | 854..858 'self': I | ||
2585 | 865..885 '{ ... }': I | ||
2586 | 875..879 'self': I | ||
2587 | 944..955 '{ loop {} }': Vec<T> | ||
2588 | 946..953 'loop {}': ! | ||
2589 | 951..953 '{}': () | ||
2590 | 1142..1269 '{ ... }); }': () | ||
2591 | 1148..1163 'Vec::<i32>::new': fn new<i32>() -> Vec<i32> | ||
2592 | 1148..1165 'Vec::<...:new()': Vec<i32> | ||
2593 | 1148..1177 'Vec::<...iter()': IntoIter<i32> | ||
2594 | 1148..1240 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>> | ||
2595 | 1148..1266 'Vec::<... y; })': () | ||
2596 | 1194..1239 '|x| if...None }': |i32| -> Option<u32> | ||
2597 | 1195..1196 'x': i32 | ||
2598 | 1198..1239 'if x >...None }': Option<u32> | ||
2599 | 1201..1202 'x': i32 | ||
2600 | 1201..1206 'x > 0': bool | ||
2601 | 1205..1206 '0': i32 | ||
2602 | 1207..1225 '{ Some...u32) }': Option<u32> | ||
2603 | 1209..1213 'Some': Some<u32>(u32) -> Option<u32> | ||
2604 | 1209..1223 'Some(x as u32)': Option<u32> | ||
2605 | 1214..1215 'x': i32 | ||
2606 | 1214..1222 'x as u32': u32 | ||
2607 | 1231..1239 '{ None }': Option<u32> | ||
2608 | 1233..1237 'None': Option<u32> | ||
2609 | 1255..1265 '|y| { y; }': |u32| -> () | ||
2610 | 1256..1257 'y': u32 | ||
2611 | 1259..1265 '{ y; }': () | ||
2612 | 1261..1262 'y': u32 | ||
2613 | "#]], | ||
2614 | ); | ||
2615 | } | ||
2616 | |||
2617 | #[test] | ||
2618 | fn nested_assoc() { | ||
2619 | check_types( | ||
2620 | r#" | ||
2621 | struct Bar; | ||
2622 | struct Foo; | ||
2623 | |||
2624 | trait A { | ||
2625 | type OutputA; | ||
2626 | } | ||
2627 | |||
2628 | impl A for Bar { | ||
2629 | type OutputA = Foo; | ||
2630 | } | ||
2631 | |||
2632 | trait B { | ||
2633 | type Output; | ||
2634 | fn foo() -> Self::Output; | ||
2635 | } | ||
2636 | |||
2637 | impl<T:A> B for T { | ||
2638 | type Output = T::OutputA; | ||
2639 | fn foo() -> Self::Output { loop {} } | ||
2640 | } | ||
2641 | |||
2642 | fn main() { | ||
2643 | Bar::foo(); | ||
2644 | } //^ Foo | ||
2645 | "#, | ||
2646 | ); | ||
2647 | } | ||
2648 | |||
2649 | #[test] | ||
2650 | fn trait_object_no_coercion() { | ||
2651 | check_infer_with_mismatches( | ||
2652 | r#" | ||
2653 | trait Foo {} | ||
2654 | |||
2655 | fn foo(x: &dyn Foo) {} | ||
2656 | |||
2657 | fn test(x: &dyn Foo) { | ||
2658 | foo(x); | ||
2659 | } | ||
2660 | "#, | ||
2661 | expect![[r#" | ||
2662 | 21..22 'x': &dyn Foo | ||
2663 | 34..36 '{}': () | ||
2664 | 46..47 'x': &dyn Foo | ||
2665 | 59..74 '{ foo(x); }': () | ||
2666 | 65..68 'foo': fn foo(&dyn Foo) | ||
2667 | 65..71 'foo(x)': () | ||
2668 | 69..70 'x': &dyn Foo | ||
2669 | "#]], | ||
2670 | ); | ||
2671 | } | ||
2672 | |||
2673 | #[test] | ||
2674 | fn builtin_copy() { | ||
2675 | check_infer_with_mismatches( | ||
2676 | r#" | ||
2677 | #[lang = "copy"] | ||
2678 | trait Copy {} | ||
2679 | |||
2680 | struct IsCopy; | ||
2681 | impl Copy for IsCopy {} | ||
2682 | struct NotCopy; | ||
2683 | |||
2684 | trait Test { fn test(&self) -> bool; } | ||
2685 | impl<T: Copy> Test for T {} | ||
2686 | |||
2687 | fn test() { | ||
2688 | IsCopy.test(); | ||
2689 | NotCopy.test(); | ||
2690 | (IsCopy, IsCopy).test(); | ||
2691 | (IsCopy, NotCopy).test(); | ||
2692 | } | ||
2693 | "#, | ||
2694 | expect![[r#" | ||
2695 | 110..114 'self': &Self | ||
2696 | 166..267 '{ ...t(); }': () | ||
2697 | 172..178 'IsCopy': IsCopy | ||
2698 | 172..185 'IsCopy.test()': bool | ||
2699 | 191..198 'NotCopy': NotCopy | ||
2700 | 191..205 'NotCopy.test()': {unknown} | ||
2701 | 211..227 '(IsCop...sCopy)': (IsCopy, IsCopy) | ||
2702 | 211..234 '(IsCop...test()': bool | ||
2703 | 212..218 'IsCopy': IsCopy | ||
2704 | 220..226 'IsCopy': IsCopy | ||
2705 | 240..257 '(IsCop...tCopy)': (IsCopy, NotCopy) | ||
2706 | 240..264 '(IsCop...test()': {unknown} | ||
2707 | 241..247 'IsCopy': IsCopy | ||
2708 | 249..256 'NotCopy': NotCopy | ||
2709 | "#]], | ||
2710 | ); | ||
2711 | } | ||
2712 | |||
2713 | #[test] | ||
2714 | fn builtin_fn_def_copy() { | ||
2715 | check_infer_with_mismatches( | ||
2716 | r#" | ||
2717 | #[lang = "copy"] | ||
2718 | trait Copy {} | ||
2719 | |||
2720 | fn foo() {} | ||
2721 | fn bar<T: Copy>(T) -> T {} | ||
2722 | struct Struct(usize); | ||
2723 | enum Enum { Variant(usize) } | ||
2724 | |||
2725 | trait Test { fn test(&self) -> bool; } | ||
2726 | impl<T: Copy> Test for T {} | ||
2727 | |||
2728 | fn test() { | ||
2729 | foo.test(); | ||
2730 | bar.test(); | ||
2731 | Struct.test(); | ||
2732 | Enum::Variant.test(); | ||
2733 | } | ||
2734 | "#, | ||
2735 | expect![[r#" | ||
2736 | 41..43 '{}': () | ||
2737 | 60..61 'T': {unknown} | ||
2738 | 68..70 '{}': () | ||
2739 | 68..70: expected T, got () | ||
2740 | 145..149 'self': &Self | ||
2741 | 201..281 '{ ...t(); }': () | ||
2742 | 207..210 'foo': fn foo() | ||
2743 | 207..217 'foo.test()': bool | ||
2744 | 223..226 'bar': fn bar<{unknown}>({unknown}) -> {unknown} | ||
2745 | 223..233 'bar.test()': bool | ||
2746 | 239..245 'Struct': Struct(usize) -> Struct | ||
2747 | 239..252 'Struct.test()': bool | ||
2748 | 258..271 'Enum::Variant': Variant(usize) -> Enum | ||
2749 | 258..278 'Enum::...test()': bool | ||
2750 | "#]], | ||
2751 | ); | ||
2752 | } | ||
2753 | |||
2754 | #[test] | ||
2755 | fn builtin_fn_ptr_copy() { | ||
2756 | check_infer_with_mismatches( | ||
2757 | r#" | ||
2758 | #[lang = "copy"] | ||
2759 | trait Copy {} | ||
2760 | |||
2761 | trait Test { fn test(&self) -> bool; } | ||
2762 | impl<T: Copy> Test for T {} | ||
2763 | |||
2764 | fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { | ||
2765 | f1.test(); | ||
2766 | f2.test(); | ||
2767 | f3.test(); | ||
2768 | } | ||
2769 | "#, | ||
2770 | expect![[r#" | ||
2771 | 54..58 'self': &Self | ||
2772 | 108..110 'f1': fn() | ||
2773 | 118..120 'f2': fn(usize) -> u8 | ||
2774 | 139..141 'f3': fn(u8, u8) -> &u8 | ||
2775 | 162..210 '{ ...t(); }': () | ||
2776 | 168..170 'f1': fn() | ||
2777 | 168..177 'f1.test()': bool | ||
2778 | 183..185 'f2': fn(usize) -> u8 | ||
2779 | 183..192 'f2.test()': bool | ||
2780 | 198..200 'f3': fn(u8, u8) -> &u8 | ||
2781 | 198..207 'f3.test()': bool | ||
2782 | "#]], | ||
2783 | ); | ||
2784 | } | ||
2785 | |||
2786 | #[test] | ||
2787 | fn builtin_sized() { | ||
2788 | check_infer_with_mismatches( | ||
2789 | r#" | ||
2790 | #[lang = "sized"] | ||
2791 | trait Sized {} | ||
2792 | |||
2793 | trait Test { fn test(&self) -> bool; } | ||
2794 | impl<T: Sized> Test for T {} | ||
2795 | |||
2796 | fn test() { | ||
2797 | 1u8.test(); | ||
2798 | (*"foo").test(); // not Sized | ||
2799 | (1u8, 1u8).test(); | ||
2800 | (1u8, *"foo").test(); // not Sized | ||
2801 | } | ||
2802 | "#, | ||
2803 | expect![[r#" | ||
2804 | 56..60 'self': &Self | ||
2805 | 113..228 '{ ...ized }': () | ||
2806 | 119..122 '1u8': u8 | ||
2807 | 119..129 '1u8.test()': bool | ||
2808 | 135..150 '(*"foo").test()': {unknown} | ||
2809 | 136..142 '*"foo"': str | ||
2810 | 137..142 '"foo"': &str | ||
2811 | 169..179 '(1u8, 1u8)': (u8, u8) | ||
2812 | 169..186 '(1u8, ...test()': bool | ||
2813 | 170..173 '1u8': u8 | ||
2814 | 175..178 '1u8': u8 | ||
2815 | 192..205 '(1u8, *"foo")': (u8, str) | ||
2816 | 192..212 '(1u8, ...test()': {unknown} | ||
2817 | 193..196 '1u8': u8 | ||
2818 | 198..204 '*"foo"': str | ||
2819 | 199..204 '"foo"': &str | ||
2820 | "#]], | ||
2821 | ); | ||
2822 | } | ||
2823 | |||
2824 | #[test] | ||
2825 | fn integer_range_iterate() { | ||
2826 | check_types( | ||
2827 | r#" | ||
2828 | //- /main.rs crate:main deps:core | ||
2829 | fn test() { | ||
2830 | for x in 0..100 { x; } | ||
2831 | } //^ i32 | ||
2832 | |||
2833 | //- /core.rs crate:core | ||
2834 | pub mod ops { | ||
2835 | pub struct Range<Idx> { | ||
2836 | pub start: Idx, | ||
2837 | pub end: Idx, | ||
2838 | } | ||
2839 | } | ||
2840 | |||
2841 | pub mod iter { | ||
2842 | pub trait Iterator { | ||
2843 | type Item; | ||
2844 | } | ||
2845 | |||
2846 | pub trait IntoIterator { | ||
2847 | type Item; | ||
2848 | type IntoIter: Iterator<Item = Self::Item>; | ||
2849 | } | ||
2850 | |||
2851 | impl<T> IntoIterator for T where T: Iterator { | ||
2852 | type Item = <T as Iterator>::Item; | ||
2853 | type IntoIter = Self; | ||
2854 | } | ||
2855 | } | ||
2856 | |||
2857 | trait Step {} | ||
2858 | impl Step for i32 {} | ||
2859 | impl Step for i64 {} | ||
2860 | |||
2861 | impl<A: Step> iter::Iterator for ops::Range<A> { | ||
2862 | type Item = A; | ||
2863 | } | ||
2864 | "#, | ||
2865 | ); | ||
2866 | } | ||
2867 | |||
2868 | #[test] | ||
2869 | fn infer_closure_arg() { | ||
2870 | check_infer( | ||
2871 | r#" | ||
2872 | //- /lib.rs | ||
2873 | |||
2874 | enum Option<T> { | ||
2875 | None, | ||
2876 | Some(T) | ||
2877 | } | ||
2878 | |||
2879 | fn foo() { | ||
2880 | let s = Option::None; | ||
2881 | let f = |x: Option<i32>| {}; | ||
2882 | (&f)(s) | ||
2883 | } | ||
2884 | "#, | ||
2885 | expect![[r#" | ||
2886 | 52..126 '{ ...)(s) }': () | ||
2887 | 62..63 's': Option<i32> | ||
2888 | 66..78 'Option::None': Option<i32> | ||
2889 | 88..89 'f': |Option<i32>| -> () | ||
2890 | 92..111 '|x: Op...2>| {}': |Option<i32>| -> () | ||
2891 | 93..94 'x': Option<i32> | ||
2892 | 109..111 '{}': () | ||
2893 | 117..124 '(&f)(s)': () | ||
2894 | 118..120 '&f': &|Option<i32>| -> () | ||
2895 | 119..120 'f': |Option<i32>| -> () | ||
2896 | 122..123 's': Option<i32> | ||
2897 | "#]], | ||
2898 | ); | ||
2899 | } | ||
2900 | |||
2901 | #[test] | ||
2902 | fn infer_fn_trait_arg() { | ||
2903 | check_infer( | ||
2904 | r#" | ||
2905 | //- /lib.rs deps:std | ||
2906 | |||
2907 | #[lang = "fn_once"] | ||
2908 | pub trait FnOnce<Args> { | ||
2909 | type Output; | ||
2910 | |||
2911 | extern "rust-call" fn call_once(&self, args: Args) -> Self::Output; | ||
2912 | } | ||
2913 | |||
2914 | #[lang = "fn"] | ||
2915 | pub trait Fn<Args>:FnOnce<Args> { | ||
2916 | extern "rust-call" fn call(&self, args: Args) -> Self::Output; | ||
2917 | } | ||
2918 | |||
2919 | enum Option<T> { | ||
2920 | None, | ||
2921 | Some(T) | ||
2922 | } | ||
2923 | |||
2924 | fn foo<F, T>(f: F) -> T | ||
2925 | where | ||
2926 | F: Fn(Option<i32>) -> T, | ||
2927 | { | ||
2928 | let s = None; | ||
2929 | f(s) | ||
2930 | } | ||
2931 | "#, | ||
2932 | expect![[r#" | ||
2933 | 101..105 'self': &Self | ||
2934 | 107..111 'args': Args | ||
2935 | 220..224 'self': &Self | ||
2936 | 226..230 'args': Args | ||
2937 | 313..314 'f': F | ||
2938 | 359..389 '{ ...f(s) }': T | ||
2939 | 369..370 's': Option<i32> | ||
2940 | 373..377 'None': Option<i32> | ||
2941 | 383..384 'f': F | ||
2942 | 383..387 'f(s)': T | ||
2943 | 385..386 's': Option<i32> | ||
2944 | "#]], | ||
2945 | ); | ||
2946 | } | ||
2947 | |||
2948 | #[test] | ||
2949 | fn infer_box_fn_arg() { | ||
2950 | check_infer( | ||
2951 | r#" | ||
2952 | //- /lib.rs deps:std | ||
2953 | |||
2954 | #[lang = "fn_once"] | ||
2955 | pub trait FnOnce<Args> { | ||
2956 | type Output; | ||
2957 | |||
2958 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
2959 | } | ||
2960 | |||
2961 | #[lang = "deref"] | ||
2962 | pub trait Deref { | ||
2963 | type Target: ?Sized; | ||
2964 | |||
2965 | fn deref(&self) -> &Self::Target; | ||
2966 | } | ||
2967 | |||
2968 | #[lang = "owned_box"] | ||
2969 | pub struct Box<T: ?Sized> { | ||
2970 | inner: *mut T, | ||
2971 | } | ||
2972 | |||
2973 | impl<T: ?Sized> Deref for Box<T> { | ||
2974 | type Target = T; | ||
2975 | |||
2976 | fn deref(&self) -> &T { | ||
2977 | &self.inner | ||
2978 | } | ||
2979 | } | ||
2980 | |||
2981 | enum Option<T> { | ||
2982 | None, | ||
2983 | Some(T) | ||
2984 | } | ||
2985 | |||
2986 | fn foo() { | ||
2987 | let s = Option::None; | ||
2988 | let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {}); | ||
2989 | f(&s) | ||
2990 | } | ||
2991 | "#, | ||
2992 | expect![[r#" | ||
2993 | 100..104 'self': Self | ||
2994 | 106..110 'args': Args | ||
2995 | 214..218 'self': &Self | ||
2996 | 384..388 'self': &Box<T> | ||
2997 | 396..423 '{ ... }': &T | ||
2998 | 406..417 '&self.inner': &*mut T | ||
2999 | 407..411 'self': &Box<T> | ||
3000 | 407..417 'self.inner': *mut T | ||
3001 | 478..575 '{ ...(&s) }': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> | ||
3002 | 488..489 's': Option<i32> | ||
3003 | 492..504 'Option::None': Option<i32> | ||
3004 | 514..515 'f': Box<dyn FnOnce<(&Option<i32>,)>> | ||
3005 | 549..562 'box (|ps| {})': Box<|{unknown}| -> ()> | ||
3006 | 554..561 '|ps| {}': |{unknown}| -> () | ||
3007 | 555..557 'ps': {unknown} | ||
3008 | 559..561 '{}': () | ||
3009 | 568..569 'f': Box<dyn FnOnce<(&Option<i32>,)>> | ||
3010 | 568..573 'f(&s)': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> | ||
3011 | 570..572 '&s': &Option<i32> | ||
3012 | 571..572 's': Option<i32> | ||
3013 | "#]], | ||
3014 | ); | ||
3015 | } | ||
3016 | |||
3017 | #[test] | ||
3018 | fn infer_dyn_fn_output() { | ||
3019 | check_types( | ||
3020 | r#" | ||
3021 | #[lang = "fn_once"] | ||
3022 | pub trait FnOnce<Args> { | ||
3023 | type Output; | ||
3024 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
3025 | } | ||
3026 | |||
3027 | #[lang = "fn"] | ||
3028 | pub trait Fn<Args>: FnOnce<Args> { | ||
3029 | extern "rust-call" fn call(&self, args: Args) -> Self::Output; | ||
3030 | } | ||
3031 | |||
3032 | fn foo() { | ||
3033 | let f: &dyn Fn() -> i32; | ||
3034 | f(); | ||
3035 | //^^^ i32 | ||
3036 | }"#, | ||
3037 | ); | ||
3038 | } | ||
3039 | |||
3040 | #[test] | ||
3041 | fn infer_dyn_fn_once_output() { | ||
3042 | check_types( | ||
3043 | r#" | ||
3044 | #[lang = "fn_once"] | ||
3045 | pub trait FnOnce<Args> { | ||
3046 | type Output; | ||
3047 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
3048 | } | ||
3049 | |||
3050 | fn foo() { | ||
3051 | let f: dyn FnOnce() -> i32; | ||
3052 | f(); | ||
3053 | //^^^ i32 | ||
3054 | }"#, | ||
3055 | ); | ||
3056 | } | ||
3057 | |||
3058 | #[test] | ||
3059 | fn variable_kinds_1() { | ||
3060 | check_types( | ||
3061 | r#" | ||
3062 | trait Trait<T> { fn get(self, t: T) -> T; } | ||
3063 | struct S; | ||
3064 | impl Trait<u128> for S {} | ||
3065 | impl Trait<f32> for S {} | ||
3066 | fn test() { | ||
3067 | S.get(1); | ||
3068 | //^^^^^^^^ u128 | ||
3069 | S.get(1.); | ||
3070 | //^^^^^^^^ f32 | ||
3071 | } | ||
3072 | "#, | ||
3073 | ); | ||
3074 | } | ||
3075 | |||
3076 | #[test] | ||
3077 | fn variable_kinds_2() { | ||
3078 | check_types( | ||
3079 | r#" | ||
3080 | trait Trait { fn get(self) -> Self; } | ||
3081 | impl Trait for u128 {} | ||
3082 | impl Trait for f32 {} | ||
3083 | fn test() { | ||
3084 | 1.get(); | ||
3085 | //^^^^^^^ u128 | ||
3086 | (1.).get(); | ||
3087 | //^^^^^^^^^^ f32 | ||
3088 | } | ||
3089 | "#, | ||
3090 | ); | ||
3091 | } | ||
3092 | |||
3093 | #[test] | ||
3094 | fn underscore_import() { | ||
3095 | check_types( | ||
3096 | r#" | ||
3097 | mod tr { | ||
3098 | pub trait Tr { | ||
3099 | fn method(&self) -> u8 { 0 } | ||
3100 | } | ||
3101 | } | ||
3102 | |||
3103 | struct Tr; | ||
3104 | impl crate::tr::Tr for Tr {} | ||
3105 | |||
3106 | use crate::tr::Tr as _; | ||
3107 | fn test() { | ||
3108 | Tr.method(); | ||
3109 | //^^^^^^^^^^^ u8 | ||
3110 | } | ||
3111 | "#, | ||
3112 | ); | ||
3113 | } | ||
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs new file mode 100644 index 000000000..14cd3a2b4 --- /dev/null +++ b/crates/hir_ty/src/traits.rs | |||
@@ -0,0 +1,285 @@ | |||
1 | //! Trait solving using Chalk. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use base_db::CrateId; | ||
5 | use chalk_ir::cast::Cast; | ||
6 | use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver}; | ||
7 | use hir_def::{lang_item::LangItemTarget, TraitId}; | ||
8 | |||
9 | use crate::{db::HirDatabase, DebruijnIndex, Substs}; | ||
10 | |||
11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; | ||
12 | |||
13 | use self::chalk::{from_chalk, Interner, ToChalk}; | ||
14 | |||
15 | pub(crate) mod chalk; | ||
16 | |||
17 | // This controls the maximum size of types Chalk considers. If we set this too | ||
18 | // high, we can run into slow edge cases; if we set it too low, Chalk won't | ||
19 | // find some solutions. | ||
20 | // FIXME this is currently hardcoded in the recursive solver | ||
21 | // const CHALK_SOLVER_MAX_SIZE: usize = 10; | ||
22 | |||
23 | /// This controls how much 'time' we give the Chalk solver before giving up. | ||
24 | const CHALK_SOLVER_FUEL: i32 = 100; | ||
25 | |||
26 | #[derive(Debug, Copy, Clone)] | ||
27 | struct ChalkContext<'a> { | ||
28 | db: &'a dyn HirDatabase, | ||
29 | krate: CrateId, | ||
30 | } | ||
31 | |||
32 | fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> { | ||
33 | let overflow_depth = 100; | ||
34 | let caching_enabled = true; | ||
35 | chalk_recursive::RecursiveSolver::new(overflow_depth, caching_enabled) | ||
36 | } | ||
37 | |||
38 | /// A set of clauses that we assume to be true. E.g. if we are inside this function: | ||
39 | /// ```rust | ||
40 | /// fn foo<T: Default>(t: T) {} | ||
41 | /// ``` | ||
42 | /// we assume that `T: Default`. | ||
43 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
44 | pub struct TraitEnvironment { | ||
45 | pub predicates: Vec<GenericPredicate>, | ||
46 | } | ||
47 | |||
48 | impl TraitEnvironment { | ||
49 | /// Returns trait refs with the given self type which are supposed to hold | ||
50 | /// in this trait env. E.g. if we are in `foo<T: SomeTrait>()`, this will | ||
51 | /// find that `T: SomeTrait` if we call it for `T`. | ||
52 | pub(crate) fn trait_predicates_for_self_ty<'a>( | ||
53 | &'a self, | ||
54 | ty: &'a Ty, | ||
55 | ) -> impl Iterator<Item = &'a TraitRef> + 'a { | ||
56 | self.predicates.iter().filter_map(move |pred| match pred { | ||
57 | GenericPredicate::Implemented(tr) if tr.self_ty() == ty => Some(tr), | ||
58 | _ => None, | ||
59 | }) | ||
60 | } | ||
61 | } | ||
62 | |||
63 | /// Something (usually a goal), along with an environment. | ||
64 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
65 | pub struct InEnvironment<T> { | ||
66 | pub environment: Arc<TraitEnvironment>, | ||
67 | pub value: T, | ||
68 | } | ||
69 | |||
70 | impl<T> InEnvironment<T> { | ||
71 | pub fn new(environment: Arc<TraitEnvironment>, value: T) -> InEnvironment<T> { | ||
72 | InEnvironment { environment, value } | ||
73 | } | ||
74 | } | ||
75 | |||
76 | /// Something that needs to be proven (by Chalk) during type checking, e.g. that | ||
77 | /// a certain type implements a certain trait. Proving the Obligation might | ||
78 | /// result in additional information about inference variables. | ||
79 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
80 | pub enum Obligation { | ||
81 | /// Prove that a certain type implements a trait (the type is the `Self` type | ||
82 | /// parameter to the `TraitRef`). | ||
83 | Trait(TraitRef), | ||
84 | Projection(ProjectionPredicate), | ||
85 | } | ||
86 | |||
87 | impl Obligation { | ||
88 | pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> { | ||
89 | match predicate { | ||
90 | GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)), | ||
91 | GenericPredicate::Projection(projection_pred) => { | ||
92 | Some(Obligation::Projection(projection_pred)) | ||
93 | } | ||
94 | GenericPredicate::Error => None, | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
100 | pub struct ProjectionPredicate { | ||
101 | pub projection_ty: ProjectionTy, | ||
102 | pub ty: Ty, | ||
103 | } | ||
104 | |||
105 | impl TypeWalk for ProjectionPredicate { | ||
106 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
107 | self.projection_ty.walk(f); | ||
108 | self.ty.walk(f); | ||
109 | } | ||
110 | |||
111 | fn walk_mut_binders( | ||
112 | &mut self, | ||
113 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
114 | binders: DebruijnIndex, | ||
115 | ) { | ||
116 | self.projection_ty.walk_mut_binders(f, binders); | ||
117 | self.ty.walk_mut_binders(f, binders); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /// Solve a trait goal using Chalk. | ||
122 | pub(crate) fn trait_solve_query( | ||
123 | db: &dyn HirDatabase, | ||
124 | krate: CrateId, | ||
125 | goal: Canonical<InEnvironment<Obligation>>, | ||
126 | ) -> Option<Solution> { | ||
127 | let _p = profile::span("trait_solve_query").detail(|| match &goal.value.value { | ||
128 | Obligation::Trait(it) => db.trait_data(it.trait_).name.to_string(), | ||
129 | Obligation::Projection(_) => "projection".to_string(), | ||
130 | }); | ||
131 | log::info!("trait_solve_query({})", goal.value.value.display(db)); | ||
132 | |||
133 | if let Obligation::Projection(pred) = &goal.value.value { | ||
134 | if let Ty::Bound(_) = &pred.projection_ty.parameters[0] { | ||
135 | // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible | ||
136 | return Some(Solution::Ambig(Guidance::Unknown)); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | let canonical = goal.to_chalk(db).cast(&Interner); | ||
141 | |||
142 | // We currently don't deal with universes (I think / hope they're not yet | ||
143 | // relevant for our use cases?) | ||
144 | let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; | ||
145 | let solution = solve(db, krate, &u_canonical); | ||
146 | solution.map(|solution| solution_from_chalk(db, solution)) | ||
147 | } | ||
148 | |||
149 | fn solve( | ||
150 | db: &dyn HirDatabase, | ||
151 | krate: CrateId, | ||
152 | goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>, | ||
153 | ) -> Option<chalk_solve::Solution<Interner>> { | ||
154 | let context = ChalkContext { db, krate }; | ||
155 | log::debug!("solve goal: {:?}", goal); | ||
156 | let mut solver = create_chalk_solver(); | ||
157 | |||
158 | let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL); | ||
159 | |||
160 | let should_continue = || { | ||
161 | context.db.check_canceled(); | ||
162 | let remaining = fuel.get(); | ||
163 | fuel.set(remaining - 1); | ||
164 | if remaining == 0 { | ||
165 | log::debug!("fuel exhausted"); | ||
166 | } | ||
167 | remaining > 0 | ||
168 | }; | ||
169 | |||
170 | let mut solve = || { | ||
171 | if is_chalk_print() { | ||
172 | let logging_db = LoggingRustIrDatabase::new(context); | ||
173 | let solution = solver.solve_limited(&logging_db, goal, &should_continue); | ||
174 | log::debug!("chalk program:\n{}", logging_db); | ||
175 | solution | ||
176 | } else { | ||
177 | solver.solve_limited(&context, goal, &should_continue) | ||
178 | } | ||
179 | }; | ||
180 | |||
181 | // don't set the TLS for Chalk unless Chalk debugging is active, to make | ||
182 | // extra sure we only use it for debugging | ||
183 | let solution = | ||
184 | if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() }; | ||
185 | |||
186 | log::debug!("solve({:?}) => {:?}", goal, solution); | ||
187 | |||
188 | solution | ||
189 | } | ||
190 | |||
191 | fn is_chalk_debug() -> bool { | ||
192 | std::env::var("CHALK_DEBUG").is_ok() | ||
193 | } | ||
194 | |||
195 | fn is_chalk_print() -> bool { | ||
196 | std::env::var("CHALK_PRINT").is_ok() | ||
197 | } | ||
198 | |||
199 | fn solution_from_chalk( | ||
200 | db: &dyn HirDatabase, | ||
201 | solution: chalk_solve::Solution<Interner>, | ||
202 | ) -> Solution { | ||
203 | let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| { | ||
204 | let result = from_chalk(db, subst); | ||
205 | SolutionVariables(result) | ||
206 | }; | ||
207 | match solution { | ||
208 | chalk_solve::Solution::Unique(constr_subst) => { | ||
209 | let subst = chalk_ir::Canonical { | ||
210 | value: constr_subst.value.subst, | ||
211 | binders: constr_subst.binders, | ||
212 | }; | ||
213 | Solution::Unique(convert_subst(subst)) | ||
214 | } | ||
215 | chalk_solve::Solution::Ambig(chalk_solve::Guidance::Definite(subst)) => { | ||
216 | Solution::Ambig(Guidance::Definite(convert_subst(subst))) | ||
217 | } | ||
218 | chalk_solve::Solution::Ambig(chalk_solve::Guidance::Suggested(subst)) => { | ||
219 | Solution::Ambig(Guidance::Suggested(convert_subst(subst))) | ||
220 | } | ||
221 | chalk_solve::Solution::Ambig(chalk_solve::Guidance::Unknown) => { | ||
222 | Solution::Ambig(Guidance::Unknown) | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | |||
227 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
228 | pub struct SolutionVariables(pub Canonical<Substs>); | ||
229 | |||
230 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
231 | /// A (possible) solution for a proposed goal. | ||
232 | pub enum Solution { | ||
233 | /// The goal indeed holds, and there is a unique value for all existential | ||
234 | /// variables. | ||
235 | Unique(SolutionVariables), | ||
236 | |||
237 | /// The goal may be provable in multiple ways, but regardless we may have some guidance | ||
238 | /// for type inference. In this case, we don't return any lifetime | ||
239 | /// constraints, since we have not "committed" to any particular solution | ||
240 | /// yet. | ||
241 | Ambig(Guidance), | ||
242 | } | ||
243 | |||
244 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
245 | /// When a goal holds ambiguously (e.g., because there are multiple possible | ||
246 | /// solutions), we issue a set of *guidance* back to type inference. | ||
247 | pub enum Guidance { | ||
248 | /// The existential variables *must* have the given values if the goal is | ||
249 | /// ever to hold, but that alone isn't enough to guarantee the goal will | ||
250 | /// actually hold. | ||
251 | Definite(SolutionVariables), | ||
252 | |||
253 | /// There are multiple plausible values for the existentials, but the ones | ||
254 | /// here are suggested as the preferred choice heuristically. These should | ||
255 | /// be used for inference fallback only. | ||
256 | Suggested(SolutionVariables), | ||
257 | |||
258 | /// There's no useful information to feed back to type inference | ||
259 | Unknown, | ||
260 | } | ||
261 | |||
262 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
263 | pub enum FnTrait { | ||
264 | FnOnce, | ||
265 | FnMut, | ||
266 | Fn, | ||
267 | } | ||
268 | |||
269 | impl FnTrait { | ||
270 | fn lang_item_name(self) -> &'static str { | ||
271 | match self { | ||
272 | FnTrait::FnOnce => "fn_once", | ||
273 | FnTrait::FnMut => "fn_mut", | ||
274 | FnTrait::Fn => "fn", | ||
275 | } | ||
276 | } | ||
277 | |||
278 | pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> { | ||
279 | let target = db.lang_item(krate, self.lang_item_name().into())?; | ||
280 | match target { | ||
281 | LangItemTarget::TraitId(t) => Some(t), | ||
282 | _ => None, | ||
283 | } | ||
284 | } | ||
285 | } | ||
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs new file mode 100644 index 000000000..17c83b6a4 --- /dev/null +++ b/crates/hir_ty/src/traits/chalk.rs | |||
@@ -0,0 +1,589 @@ | |||
1 | //! Conversion code from/to Chalk. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use log::debug; | ||
5 | |||
6 | use chalk_ir::{fold::shift::Shift, CanonicalVarKinds, GenericArg, TypeName}; | ||
7 | use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; | ||
8 | |||
9 | use base_db::{salsa::InternKey, CrateId}; | ||
10 | use hir_def::{ | ||
11 | lang_item::{lang_attr, LangItemTarget}, | ||
12 | AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId, | ||
13 | }; | ||
14 | |||
15 | use super::ChalkContext; | ||
16 | use crate::{ | ||
17 | db::HirDatabase, | ||
18 | display::HirDisplay, | ||
19 | method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, | ||
20 | utils::generics, | ||
21 | CallableDefId, DebruijnIndex, FnSig, GenericPredicate, Substs, Ty, TypeCtor, | ||
22 | }; | ||
23 | use mapping::{ | ||
24 | convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, | ||
25 | }; | ||
26 | |||
27 | pub use self::interner::*; | ||
28 | |||
29 | pub(super) mod tls; | ||
30 | mod interner; | ||
31 | mod mapping; | ||
32 | |||
33 | pub(super) trait ToChalk { | ||
34 | type Chalk; | ||
35 | fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk; | ||
36 | fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self; | ||
37 | } | ||
38 | |||
39 | pub(super) fn from_chalk<T, ChalkT>(db: &dyn HirDatabase, chalk: ChalkT) -> T | ||
40 | where | ||
41 | T: ToChalk<Chalk = ChalkT>, | ||
42 | { | ||
43 | T::from_chalk(db, chalk) | ||
44 | } | ||
45 | |||
46 | impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | ||
47 | fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { | ||
48 | self.db.associated_ty_data(id) | ||
49 | } | ||
50 | fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> { | ||
51 | self.db.trait_datum(self.krate, trait_id) | ||
52 | } | ||
53 | fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> { | ||
54 | self.db.struct_datum(self.krate, struct_id) | ||
55 | } | ||
56 | fn adt_repr(&self, _struct_id: AdtId) -> rust_ir::AdtRepr { | ||
57 | rust_ir::AdtRepr { repr_c: false, repr_packed: false } | ||
58 | } | ||
59 | fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { | ||
60 | self.db.impl_datum(self.krate, impl_id) | ||
61 | } | ||
62 | |||
63 | fn fn_def_datum( | ||
64 | &self, | ||
65 | fn_def_id: chalk_ir::FnDefId<Interner>, | ||
66 | ) -> Arc<rust_ir::FnDefDatum<Interner>> { | ||
67 | self.db.fn_def_datum(self.krate, fn_def_id) | ||
68 | } | ||
69 | |||
70 | fn impls_for_trait( | ||
71 | &self, | ||
72 | trait_id: TraitId, | ||
73 | parameters: &[GenericArg<Interner>], | ||
74 | binders: &CanonicalVarKinds<Interner>, | ||
75 | ) -> Vec<ImplId> { | ||
76 | debug!("impls_for_trait {:?}", trait_id); | ||
77 | let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); | ||
78 | |||
79 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone()); | ||
80 | |||
81 | fn binder_kind(ty: &Ty, binders: &CanonicalVarKinds<Interner>) -> Option<chalk_ir::TyKind> { | ||
82 | if let Ty::Bound(bv) = ty { | ||
83 | let binders = binders.as_slice(&Interner); | ||
84 | if bv.debruijn == DebruijnIndex::INNERMOST { | ||
85 | if let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind { | ||
86 | return Some(tk); | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | None | ||
91 | } | ||
92 | |||
93 | let self_ty_fp = TyFingerprint::for_impl(&ty); | ||
94 | let fps: &[TyFingerprint] = match binder_kind(&ty, binders) { | ||
95 | Some(chalk_ir::TyKind::Integer) => &ALL_INT_FPS, | ||
96 | Some(chalk_ir::TyKind::Float) => &ALL_FLOAT_FPS, | ||
97 | _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]), | ||
98 | }; | ||
99 | |||
100 | // Note: Since we're using impls_for_trait, only impls where the trait | ||
101 | // can be resolved should ever reach Chalk. `impl_datum` relies on that | ||
102 | // and will panic if the trait can't be resolved. | ||
103 | let in_deps = self.db.trait_impls_in_deps(self.krate); | ||
104 | let in_self = self.db.trait_impls_in_crate(self.krate); | ||
105 | let impl_maps = [in_deps, in_self]; | ||
106 | |||
107 | let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db); | ||
108 | |||
109 | let result: Vec<_> = if fps.is_empty() { | ||
110 | debug!("Unrestricted search for {:?} impls...", trait_); | ||
111 | impl_maps | ||
112 | .iter() | ||
113 | .flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk)) | ||
114 | .collect() | ||
115 | } else { | ||
116 | impl_maps | ||
117 | .iter() | ||
118 | .flat_map(|crate_impl_defs| { | ||
119 | fps.iter().flat_map(move |fp| { | ||
120 | crate_impl_defs.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) | ||
121 | }) | ||
122 | }) | ||
123 | .collect() | ||
124 | }; | ||
125 | |||
126 | debug!("impls_for_trait returned {} impls", result.len()); | ||
127 | result | ||
128 | } | ||
129 | fn impl_provided_for(&self, auto_trait_id: TraitId, struct_id: AdtId) -> bool { | ||
130 | debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); | ||
131 | false // FIXME | ||
132 | } | ||
133 | fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> { | ||
134 | self.db.associated_ty_value(self.krate, id) | ||
135 | } | ||
136 | |||
137 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<Interner>> { | ||
138 | vec![] | ||
139 | } | ||
140 | fn local_impls_to_coherence_check(&self, _trait_id: TraitId) -> Vec<ImplId> { | ||
141 | // We don't do coherence checking (yet) | ||
142 | unimplemented!() | ||
143 | } | ||
144 | fn interner(&self) -> &Interner { | ||
145 | &Interner | ||
146 | } | ||
147 | fn well_known_trait_id( | ||
148 | &self, | ||
149 | well_known_trait: rust_ir::WellKnownTrait, | ||
150 | ) -> Option<chalk_ir::TraitId<Interner>> { | ||
151 | let lang_attr = lang_attr_from_well_known_trait(well_known_trait); | ||
152 | let trait_ = match self.db.lang_item(self.krate, lang_attr.into()) { | ||
153 | Some(LangItemTarget::TraitId(trait_)) => trait_, | ||
154 | _ => return None, | ||
155 | }; | ||
156 | Some(trait_.to_chalk(self.db)) | ||
157 | } | ||
158 | |||
159 | fn program_clauses_for_env( | ||
160 | &self, | ||
161 | environment: &chalk_ir::Environment<Interner>, | ||
162 | ) -> chalk_ir::ProgramClauses<Interner> { | ||
163 | self.db.program_clauses_for_chalk_env(self.krate, environment.clone()) | ||
164 | } | ||
165 | |||
166 | fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> { | ||
167 | let interned_id = crate::db::InternedOpaqueTyId::from(id); | ||
168 | let full_id = self.db.lookup_intern_impl_trait_id(interned_id); | ||
169 | let (func, idx) = match full_id { | ||
170 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => (func, idx), | ||
171 | }; | ||
172 | let datas = | ||
173 | self.db.return_type_impl_traits(func).expect("impl trait id without impl traits"); | ||
174 | let data = &datas.value.impl_traits[idx as usize]; | ||
175 | let bound = OpaqueTyDatumBound { | ||
176 | bounds: make_binders( | ||
177 | data.bounds | ||
178 | .value | ||
179 | .iter() | ||
180 | .cloned() | ||
181 | .filter(|b| !b.is_error()) | ||
182 | .map(|b| b.to_chalk(self.db)) | ||
183 | .collect(), | ||
184 | 1, | ||
185 | ), | ||
186 | where_clauses: make_binders(vec![], 0), | ||
187 | }; | ||
188 | let num_vars = datas.num_binders; | ||
189 | Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) }) | ||
190 | } | ||
191 | |||
192 | fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { | ||
193 | // FIXME: actually provide the hidden type; it is relevant for auto traits | ||
194 | Ty::Unknown.to_chalk(self.db) | ||
195 | } | ||
196 | |||
197 | fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool { | ||
198 | // FIXME: implement actual object safety | ||
199 | true | ||
200 | } | ||
201 | |||
202 | fn closure_kind( | ||
203 | &self, | ||
204 | _closure_id: chalk_ir::ClosureId<Interner>, | ||
205 | _substs: &chalk_ir::Substitution<Interner>, | ||
206 | ) -> rust_ir::ClosureKind { | ||
207 | // Fn is the closure kind that implements all three traits | ||
208 | rust_ir::ClosureKind::Fn | ||
209 | } | ||
210 | fn closure_inputs_and_output( | ||
211 | &self, | ||
212 | _closure_id: chalk_ir::ClosureId<Interner>, | ||
213 | substs: &chalk_ir::Substitution<Interner>, | ||
214 | ) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> { | ||
215 | let sig_ty: Ty = | ||
216 | from_chalk(self.db, substs.at(&Interner, 0).assert_ty_ref(&Interner).clone()); | ||
217 | let sig = FnSig::from_fn_ptr_substs( | ||
218 | &sig_ty.substs().expect("first closure param should be fn ptr"), | ||
219 | false, | ||
220 | ); | ||
221 | let io = rust_ir::FnDefInputsAndOutputDatum { | ||
222 | argument_types: sig.params().iter().map(|ty| ty.clone().to_chalk(self.db)).collect(), | ||
223 | return_type: sig.ret().clone().to_chalk(self.db), | ||
224 | }; | ||
225 | make_binders(io.shifted_in(&Interner), 0) | ||
226 | } | ||
227 | fn closure_upvars( | ||
228 | &self, | ||
229 | _closure_id: chalk_ir::ClosureId<Interner>, | ||
230 | _substs: &chalk_ir::Substitution<Interner>, | ||
231 | ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> { | ||
232 | let ty = Ty::unit().to_chalk(self.db); | ||
233 | make_binders(ty, 0) | ||
234 | } | ||
235 | fn closure_fn_substitution( | ||
236 | &self, | ||
237 | _closure_id: chalk_ir::ClosureId<Interner>, | ||
238 | _substs: &chalk_ir::Substitution<Interner>, | ||
239 | ) -> chalk_ir::Substitution<Interner> { | ||
240 | Substs::empty().to_chalk(self.db) | ||
241 | } | ||
242 | |||
243 | fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String { | ||
244 | let id = from_chalk(self.db, trait_id); | ||
245 | self.db.trait_data(id).name.to_string() | ||
246 | } | ||
247 | // FIXME: lookup names | ||
248 | fn adt_name(&self, struct_id: chalk_ir::AdtId<Interner>) -> String { | ||
249 | let datum = self.db.struct_datum(self.krate, struct_id); | ||
250 | format!("{:?}", datum.name(&Interner)) | ||
251 | } | ||
252 | fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String { | ||
253 | format!("Assoc_{}", assoc_ty_id.0) | ||
254 | } | ||
255 | fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId<Interner>) -> String { | ||
256 | format!("Opaque_{}", opaque_ty_id.0) | ||
257 | } | ||
258 | fn fn_def_name(&self, fn_def_id: chalk_ir::FnDefId<Interner>) -> String { | ||
259 | format!("fn_{}", fn_def_id.0) | ||
260 | } | ||
261 | } | ||
262 | |||
263 | pub(crate) fn program_clauses_for_chalk_env_query( | ||
264 | db: &dyn HirDatabase, | ||
265 | krate: CrateId, | ||
266 | environment: chalk_ir::Environment<Interner>, | ||
267 | ) -> chalk_ir::ProgramClauses<Interner> { | ||
268 | chalk_solve::program_clauses_for_env(&ChalkContext { db, krate }, &environment) | ||
269 | } | ||
270 | |||
271 | pub(crate) fn associated_ty_data_query( | ||
272 | db: &dyn HirDatabase, | ||
273 | id: AssocTypeId, | ||
274 | ) -> Arc<AssociatedTyDatum> { | ||
275 | debug!("associated_ty_data {:?}", id); | ||
276 | let type_alias: TypeAliasId = from_chalk(db, id); | ||
277 | let trait_ = match type_alias.lookup(db.upcast()).container { | ||
278 | AssocContainerId::TraitId(t) => t, | ||
279 | _ => panic!("associated type not in trait"), | ||
280 | }; | ||
281 | |||
282 | // Lower bounds -- we could/should maybe move this to a separate query in `lower` | ||
283 | let type_alias_data = db.type_alias_data(type_alias); | ||
284 | let generic_params = generics(db.upcast(), type_alias.into()); | ||
285 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
286 | let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); | ||
287 | let ctx = crate::TyLoweringContext::new(db, &resolver) | ||
288 | .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable); | ||
289 | let self_ty = Ty::Bound(crate::BoundVar::new(crate::DebruijnIndex::INNERMOST, 0)); | ||
290 | let bounds = type_alias_data | ||
291 | .bounds | ||
292 | .iter() | ||
293 | .flat_map(|bound| GenericPredicate::from_type_bound(&ctx, bound, self_ty.clone())) | ||
294 | .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) | ||
295 | .map(|bound| make_binders(bound.shifted_in(&Interner), 0)) | ||
296 | .collect(); | ||
297 | |||
298 | let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); | ||
299 | let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; | ||
300 | let datum = AssociatedTyDatum { | ||
301 | trait_id: trait_.to_chalk(db), | ||
302 | id, | ||
303 | name: type_alias, | ||
304 | binders: make_binders(bound_data, generic_params.len()), | ||
305 | }; | ||
306 | Arc::new(datum) | ||
307 | } | ||
308 | |||
309 | pub(crate) fn trait_datum_query( | ||
310 | db: &dyn HirDatabase, | ||
311 | krate: CrateId, | ||
312 | trait_id: TraitId, | ||
313 | ) -> Arc<TraitDatum> { | ||
314 | debug!("trait_datum {:?}", trait_id); | ||
315 | let trait_: hir_def::TraitId = from_chalk(db, trait_id); | ||
316 | let trait_data = db.trait_data(trait_); | ||
317 | debug!("trait {:?} = {:?}", trait_id, trait_data.name); | ||
318 | let generic_params = generics(db.upcast(), trait_.into()); | ||
319 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
320 | let flags = rust_ir::TraitFlags { | ||
321 | auto: trait_data.auto, | ||
322 | upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate, | ||
323 | non_enumerable: true, | ||
324 | coinductive: false, // only relevant for Chalk testing | ||
325 | // FIXME: set these flags correctly | ||
326 | marker: false, | ||
327 | fundamental: false, | ||
328 | }; | ||
329 | let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); | ||
330 | let associated_ty_ids = | ||
331 | trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); | ||
332 | let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses }; | ||
333 | let well_known = | ||
334 | lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); | ||
335 | let trait_datum = TraitDatum { | ||
336 | id: trait_id, | ||
337 | binders: make_binders(trait_datum_bound, bound_vars.len()), | ||
338 | flags, | ||
339 | associated_ty_ids, | ||
340 | well_known, | ||
341 | }; | ||
342 | Arc::new(trait_datum) | ||
343 | } | ||
344 | |||
345 | fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> { | ||
346 | Some(match name { | ||
347 | "sized" => WellKnownTrait::Sized, | ||
348 | "copy" => WellKnownTrait::Copy, | ||
349 | "clone" => WellKnownTrait::Clone, | ||
350 | "drop" => WellKnownTrait::Drop, | ||
351 | "fn_once" => WellKnownTrait::FnOnce, | ||
352 | "fn_mut" => WellKnownTrait::FnMut, | ||
353 | "fn" => WellKnownTrait::Fn, | ||
354 | "unsize" => WellKnownTrait::Unsize, | ||
355 | _ => return None, | ||
356 | }) | ||
357 | } | ||
358 | |||
359 | fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str { | ||
360 | match attr { | ||
361 | WellKnownTrait::Sized => "sized", | ||
362 | WellKnownTrait::Copy => "copy", | ||
363 | WellKnownTrait::Clone => "clone", | ||
364 | WellKnownTrait::Drop => "drop", | ||
365 | WellKnownTrait::FnOnce => "fn_once", | ||
366 | WellKnownTrait::FnMut => "fn_mut", | ||
367 | WellKnownTrait::Fn => "fn", | ||
368 | WellKnownTrait::Unsize => "unsize", | ||
369 | } | ||
370 | } | ||
371 | |||
372 | pub(crate) fn struct_datum_query( | ||
373 | db: &dyn HirDatabase, | ||
374 | krate: CrateId, | ||
375 | struct_id: AdtId, | ||
376 | ) -> Arc<StructDatum> { | ||
377 | debug!("struct_datum {:?}", struct_id); | ||
378 | let type_ctor: TypeCtor = from_chalk(db, TypeName::Adt(struct_id)); | ||
379 | debug!("struct {:?} = {:?}", struct_id, type_ctor); | ||
380 | let num_params = type_ctor.num_ty_params(db); | ||
381 | let upstream = type_ctor.krate(db) != Some(krate); | ||
382 | let where_clauses = type_ctor | ||
383 | .as_generic_def() | ||
384 | .map(|generic_def| { | ||
385 | let generic_params = generics(db.upcast(), generic_def); | ||
386 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
387 | convert_where_clauses(db, generic_def, &bound_vars) | ||
388 | }) | ||
389 | .unwrap_or_else(Vec::new); | ||
390 | let flags = rust_ir::AdtFlags { | ||
391 | upstream, | ||
392 | // FIXME set fundamental and phantom_data flags correctly | ||
393 | fundamental: false, | ||
394 | phantom_data: false, | ||
395 | }; | ||
396 | // FIXME provide enum variants properly (for auto traits) | ||
397 | let variant = rust_ir::AdtVariantDatum { | ||
398 | fields: Vec::new(), // FIXME add fields (only relevant for auto traits), | ||
399 | }; | ||
400 | let struct_datum_bound = rust_ir::AdtDatumBound { variants: vec![variant], where_clauses }; | ||
401 | let struct_datum = StructDatum { | ||
402 | // FIXME set ADT kind | ||
403 | kind: rust_ir::AdtKind::Struct, | ||
404 | id: struct_id, | ||
405 | binders: make_binders(struct_datum_bound, num_params), | ||
406 | flags, | ||
407 | }; | ||
408 | Arc::new(struct_datum) | ||
409 | } | ||
410 | |||
411 | pub(crate) fn impl_datum_query( | ||
412 | db: &dyn HirDatabase, | ||
413 | krate: CrateId, | ||
414 | impl_id: ImplId, | ||
415 | ) -> Arc<ImplDatum> { | ||
416 | let _p = profile::span("impl_datum"); | ||
417 | debug!("impl_datum {:?}", impl_id); | ||
418 | let impl_: hir_def::ImplId = from_chalk(db, impl_id); | ||
419 | impl_def_datum(db, krate, impl_id, impl_) | ||
420 | } | ||
421 | |||
422 | fn impl_def_datum( | ||
423 | db: &dyn HirDatabase, | ||
424 | krate: CrateId, | ||
425 | chalk_id: ImplId, | ||
426 | impl_id: hir_def::ImplId, | ||
427 | ) -> Arc<ImplDatum> { | ||
428 | let trait_ref = db | ||
429 | .impl_trait(impl_id) | ||
430 | // ImplIds for impls where the trait ref can't be resolved should never reach Chalk | ||
431 | .expect("invalid impl passed to Chalk") | ||
432 | .value; | ||
433 | let impl_data = db.impl_data(impl_id); | ||
434 | |||
435 | let generic_params = generics(db.upcast(), impl_id.into()); | ||
436 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
437 | let trait_ = trait_ref.trait_; | ||
438 | let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate { | ||
439 | rust_ir::ImplType::Local | ||
440 | } else { | ||
441 | rust_ir::ImplType::External | ||
442 | }; | ||
443 | let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars); | ||
444 | let negative = impl_data.is_negative; | ||
445 | debug!( | ||
446 | "impl {:?}: {}{} where {:?}", | ||
447 | chalk_id, | ||
448 | if negative { "!" } else { "" }, | ||
449 | trait_ref.display(db), | ||
450 | where_clauses | ||
451 | ); | ||
452 | let trait_ref = trait_ref.to_chalk(db); | ||
453 | |||
454 | let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive }; | ||
455 | |||
456 | let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses }; | ||
457 | let trait_data = db.trait_data(trait_); | ||
458 | let associated_ty_value_ids = impl_data | ||
459 | .items | ||
460 | .iter() | ||
461 | .filter_map(|item| match item { | ||
462 | AssocItemId::TypeAliasId(type_alias) => Some(*type_alias), | ||
463 | _ => None, | ||
464 | }) | ||
465 | .filter(|&type_alias| { | ||
466 | // don't include associated types that don't exist in the trait | ||
467 | let name = &db.type_alias_data(type_alias).name; | ||
468 | trait_data.associated_type_by_name(name).is_some() | ||
469 | }) | ||
470 | .map(|type_alias| TypeAliasAsValue(type_alias).to_chalk(db)) | ||
471 | .collect(); | ||
472 | debug!("impl_datum: {:?}", impl_datum_bound); | ||
473 | let impl_datum = ImplDatum { | ||
474 | binders: make_binders(impl_datum_bound, bound_vars.len()), | ||
475 | impl_type, | ||
476 | polarity, | ||
477 | associated_ty_value_ids, | ||
478 | }; | ||
479 | Arc::new(impl_datum) | ||
480 | } | ||
481 | |||
482 | pub(crate) fn associated_ty_value_query( | ||
483 | db: &dyn HirDatabase, | ||
484 | krate: CrateId, | ||
485 | id: AssociatedTyValueId, | ||
486 | ) -> Arc<AssociatedTyValue> { | ||
487 | let type_alias: TypeAliasAsValue = from_chalk(db, id); | ||
488 | type_alias_associated_ty_value(db, krate, type_alias.0) | ||
489 | } | ||
490 | |||
491 | fn type_alias_associated_ty_value( | ||
492 | db: &dyn HirDatabase, | ||
493 | _krate: CrateId, | ||
494 | type_alias: TypeAliasId, | ||
495 | ) -> Arc<AssociatedTyValue> { | ||
496 | let type_alias_data = db.type_alias_data(type_alias); | ||
497 | let impl_id = match type_alias.lookup(db.upcast()).container { | ||
498 | AssocContainerId::ImplId(it) => it, | ||
499 | _ => panic!("assoc ty value should be in impl"), | ||
500 | }; | ||
501 | |||
502 | let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist").value; // we don't return any assoc ty values if the impl'd trait can't be resolved | ||
503 | |||
504 | let assoc_ty = db | ||
505 | .trait_data(trait_ref.trait_) | ||
506 | .associated_type_by_name(&type_alias_data.name) | ||
507 | .expect("assoc ty value should not exist"); // validated when building the impl data as well | ||
508 | let ty = db.ty(type_alias.into()); | ||
509 | let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; | ||
510 | let value = rust_ir::AssociatedTyValue { | ||
511 | impl_id: impl_id.to_chalk(db), | ||
512 | associated_ty_id: assoc_ty.to_chalk(db), | ||
513 | value: make_binders(value_bound, ty.num_binders), | ||
514 | }; | ||
515 | Arc::new(value) | ||
516 | } | ||
517 | |||
518 | pub(crate) fn fn_def_datum_query( | ||
519 | db: &dyn HirDatabase, | ||
520 | _krate: CrateId, | ||
521 | fn_def_id: FnDefId, | ||
522 | ) -> Arc<FnDefDatum> { | ||
523 | let callable_def: CallableDefId = from_chalk(db, fn_def_id); | ||
524 | let generic_params = generics(db.upcast(), callable_def.into()); | ||
525 | let sig = db.callable_item_signature(callable_def); | ||
526 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
527 | let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); | ||
528 | let bound = rust_ir::FnDefDatumBound { | ||
529 | // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway | ||
530 | inputs_and_output: make_binders( | ||
531 | rust_ir::FnDefInputsAndOutputDatum { | ||
532 | argument_types: sig | ||
533 | .value | ||
534 | .params() | ||
535 | .iter() | ||
536 | .map(|ty| ty.clone().to_chalk(db)) | ||
537 | .collect(), | ||
538 | return_type: sig.value.ret().clone().to_chalk(db), | ||
539 | } | ||
540 | .shifted_in(&Interner), | ||
541 | 0, | ||
542 | ), | ||
543 | where_clauses, | ||
544 | }; | ||
545 | let datum = FnDefDatum { | ||
546 | id: fn_def_id, | ||
547 | abi: (), | ||
548 | safety: chalk_ir::Safety::Safe, | ||
549 | variadic: sig.value.is_varargs, | ||
550 | binders: make_binders(bound, sig.num_binders), | ||
551 | }; | ||
552 | Arc::new(datum) | ||
553 | } | ||
554 | |||
555 | impl From<FnDefId> for crate::db::InternedCallableDefId { | ||
556 | fn from(fn_def_id: FnDefId) -> Self { | ||
557 | InternKey::from_intern_id(fn_def_id.0) | ||
558 | } | ||
559 | } | ||
560 | |||
561 | impl From<crate::db::InternedCallableDefId> for FnDefId { | ||
562 | fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self { | ||
563 | chalk_ir::FnDefId(callable_def_id.as_intern_id()) | ||
564 | } | ||
565 | } | ||
566 | |||
567 | impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId { | ||
568 | fn from(id: OpaqueTyId) -> Self { | ||
569 | InternKey::from_intern_id(id.0) | ||
570 | } | ||
571 | } | ||
572 | |||
573 | impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId { | ||
574 | fn from(id: crate::db::InternedOpaqueTyId) -> Self { | ||
575 | chalk_ir::OpaqueTyId(id.as_intern_id()) | ||
576 | } | ||
577 | } | ||
578 | |||
579 | impl From<chalk_ir::ClosureId<Interner>> for crate::db::ClosureId { | ||
580 | fn from(id: chalk_ir::ClosureId<Interner>) -> Self { | ||
581 | Self::from_intern_id(id.0) | ||
582 | } | ||
583 | } | ||
584 | |||
585 | impl From<crate::db::ClosureId> for chalk_ir::ClosureId<Interner> { | ||
586 | fn from(id: crate::db::ClosureId) -> Self { | ||
587 | chalk_ir::ClosureId(id.as_intern_id()) | ||
588 | } | ||
589 | } | ||
diff --git a/crates/hir_ty/src/traits/chalk/interner.rs b/crates/hir_ty/src/traits/chalk/interner.rs new file mode 100644 index 000000000..fc0f9c201 --- /dev/null +++ b/crates/hir_ty/src/traits/chalk/interner.rs | |||
@@ -0,0 +1,383 @@ | |||
1 | //! Implementation of the Chalk `Interner` trait, which allows customizing the | ||
2 | //! representation of the various objects Chalk deals with (types, goals etc.). | ||
3 | |||
4 | use super::tls; | ||
5 | use base_db::salsa::InternId; | ||
6 | use chalk_ir::{GenericArg, Goal, GoalData}; | ||
7 | use hir_def::TypeAliasId; | ||
8 | use std::{fmt, sync::Arc}; | ||
9 | |||
10 | #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] | ||
11 | pub struct Interner; | ||
12 | |||
13 | pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; | ||
14 | pub type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>; | ||
15 | pub type TraitId = chalk_ir::TraitId<Interner>; | ||
16 | pub type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>; | ||
17 | pub type AdtId = chalk_ir::AdtId<Interner>; | ||
18 | pub type StructDatum = chalk_solve::rust_ir::AdtDatum<Interner>; | ||
19 | pub type ImplId = chalk_ir::ImplId<Interner>; | ||
20 | pub type ImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>; | ||
21 | pub type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId<Interner>; | ||
22 | pub type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>; | ||
23 | pub type FnDefId = chalk_ir::FnDefId<Interner>; | ||
24 | pub type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>; | ||
25 | pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>; | ||
26 | pub type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>; | ||
27 | |||
28 | impl chalk_ir::interner::Interner for Interner { | ||
29 | type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc? | ||
30 | type InternedLifetime = chalk_ir::LifetimeData<Self>; | ||
31 | type InternedConst = Arc<chalk_ir::ConstData<Self>>; | ||
32 | type InternedConcreteConst = (); | ||
33 | type InternedGenericArg = chalk_ir::GenericArgData<Self>; | ||
34 | type InternedGoal = Arc<GoalData<Self>>; | ||
35 | type InternedGoals = Vec<Goal<Self>>; | ||
36 | type InternedSubstitution = Vec<GenericArg<Self>>; | ||
37 | type InternedProgramClause = chalk_ir::ProgramClauseData<Self>; | ||
38 | type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>; | ||
39 | type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; | ||
40 | type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>; | ||
41 | type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>; | ||
42 | type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>; | ||
43 | type DefId = InternId; | ||
44 | type InternedAdtId = hir_def::AdtId; | ||
45 | type Identifier = TypeAliasId; | ||
46 | type FnAbi = (); | ||
47 | |||
48 | fn debug_adt_id(type_kind_id: AdtId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
49 | tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) | ||
50 | } | ||
51 | |||
52 | fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
53 | tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) | ||
54 | } | ||
55 | |||
56 | fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
57 | tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) | ||
58 | } | ||
59 | |||
60 | fn debug_alias( | ||
61 | alias: &chalk_ir::AliasTy<Interner>, | ||
62 | fmt: &mut fmt::Formatter<'_>, | ||
63 | ) -> Option<fmt::Result> { | ||
64 | tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt))) | ||
65 | } | ||
66 | |||
67 | fn debug_projection_ty( | ||
68 | proj: &chalk_ir::ProjectionTy<Interner>, | ||
69 | fmt: &mut fmt::Formatter<'_>, | ||
70 | ) -> Option<fmt::Result> { | ||
71 | tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt))) | ||
72 | } | ||
73 | |||
74 | fn debug_opaque_ty( | ||
75 | opaque_ty: &chalk_ir::OpaqueTy<Interner>, | ||
76 | fmt: &mut fmt::Formatter<'_>, | ||
77 | ) -> Option<fmt::Result> { | ||
78 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty(opaque_ty, fmt))) | ||
79 | } | ||
80 | |||
81 | fn debug_opaque_ty_id( | ||
82 | opaque_ty_id: chalk_ir::OpaqueTyId<Self>, | ||
83 | fmt: &mut fmt::Formatter<'_>, | ||
84 | ) -> Option<fmt::Result> { | ||
85 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty_id(opaque_ty_id, fmt))) | ||
86 | } | ||
87 | |||
88 | fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
89 | tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt))) | ||
90 | } | ||
91 | |||
92 | fn debug_lifetime( | ||
93 | lifetime: &chalk_ir::Lifetime<Interner>, | ||
94 | fmt: &mut fmt::Formatter<'_>, | ||
95 | ) -> Option<fmt::Result> { | ||
96 | tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt))) | ||
97 | } | ||
98 | |||
99 | fn debug_generic_arg( | ||
100 | parameter: &GenericArg<Interner>, | ||
101 | fmt: &mut fmt::Formatter<'_>, | ||
102 | ) -> Option<fmt::Result> { | ||
103 | tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt))) | ||
104 | } | ||
105 | |||
106 | fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
107 | tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt))) | ||
108 | } | ||
109 | |||
110 | fn debug_goals( | ||
111 | goals: &chalk_ir::Goals<Interner>, | ||
112 | fmt: &mut fmt::Formatter<'_>, | ||
113 | ) -> Option<fmt::Result> { | ||
114 | tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt))) | ||
115 | } | ||
116 | |||
117 | fn debug_program_clause_implication( | ||
118 | pci: &chalk_ir::ProgramClauseImplication<Interner>, | ||
119 | fmt: &mut fmt::Formatter<'_>, | ||
120 | ) -> Option<fmt::Result> { | ||
121 | tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt))) | ||
122 | } | ||
123 | |||
124 | fn debug_application_ty( | ||
125 | application_ty: &chalk_ir::ApplicationTy<Interner>, | ||
126 | fmt: &mut fmt::Formatter<'_>, | ||
127 | ) -> Option<fmt::Result> { | ||
128 | tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt))) | ||
129 | } | ||
130 | |||
131 | fn debug_substitution( | ||
132 | substitution: &chalk_ir::Substitution<Interner>, | ||
133 | fmt: &mut fmt::Formatter<'_>, | ||
134 | ) -> Option<fmt::Result> { | ||
135 | tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt))) | ||
136 | } | ||
137 | |||
138 | fn debug_separator_trait_ref( | ||
139 | separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>, | ||
140 | fmt: &mut fmt::Formatter<'_>, | ||
141 | ) -> Option<fmt::Result> { | ||
142 | tls::with_current_program(|prog| { | ||
143 | Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt)) | ||
144 | }) | ||
145 | } | ||
146 | |||
147 | fn debug_fn_def_id( | ||
148 | fn_def_id: chalk_ir::FnDefId<Self>, | ||
149 | fmt: &mut fmt::Formatter<'_>, | ||
150 | ) -> Option<fmt::Result> { | ||
151 | tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt))) | ||
152 | } | ||
153 | fn debug_const( | ||
154 | constant: &chalk_ir::Const<Self>, | ||
155 | fmt: &mut fmt::Formatter<'_>, | ||
156 | ) -> Option<fmt::Result> { | ||
157 | tls::with_current_program(|prog| Some(prog?.debug_const(constant, fmt))) | ||
158 | } | ||
159 | fn debug_variable_kinds( | ||
160 | variable_kinds: &chalk_ir::VariableKinds<Self>, | ||
161 | fmt: &mut fmt::Formatter<'_>, | ||
162 | ) -> Option<fmt::Result> { | ||
163 | tls::with_current_program(|prog| Some(prog?.debug_variable_kinds(variable_kinds, fmt))) | ||
164 | } | ||
165 | fn debug_variable_kinds_with_angles( | ||
166 | variable_kinds: &chalk_ir::VariableKinds<Self>, | ||
167 | fmt: &mut fmt::Formatter<'_>, | ||
168 | ) -> Option<fmt::Result> { | ||
169 | tls::with_current_program(|prog| { | ||
170 | Some(prog?.debug_variable_kinds_with_angles(variable_kinds, fmt)) | ||
171 | }) | ||
172 | } | ||
173 | fn debug_canonical_var_kinds( | ||
174 | canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Self>, | ||
175 | fmt: &mut fmt::Formatter<'_>, | ||
176 | ) -> Option<fmt::Result> { | ||
177 | tls::with_current_program(|prog| { | ||
178 | Some(prog?.debug_canonical_var_kinds(canonical_var_kinds, fmt)) | ||
179 | }) | ||
180 | } | ||
181 | fn debug_program_clause( | ||
182 | clause: &chalk_ir::ProgramClause<Self>, | ||
183 | fmt: &mut fmt::Formatter<'_>, | ||
184 | ) -> Option<fmt::Result> { | ||
185 | tls::with_current_program(|prog| Some(prog?.debug_program_clause(clause, fmt))) | ||
186 | } | ||
187 | fn debug_program_clauses( | ||
188 | clauses: &chalk_ir::ProgramClauses<Self>, | ||
189 | fmt: &mut fmt::Formatter<'_>, | ||
190 | ) -> Option<fmt::Result> { | ||
191 | tls::with_current_program(|prog| Some(prog?.debug_program_clauses(clauses, fmt))) | ||
192 | } | ||
193 | fn debug_quantified_where_clauses( | ||
194 | clauses: &chalk_ir::QuantifiedWhereClauses<Self>, | ||
195 | fmt: &mut fmt::Formatter<'_>, | ||
196 | ) -> Option<fmt::Result> { | ||
197 | tls::with_current_program(|prog| Some(prog?.debug_quantified_where_clauses(clauses, fmt))) | ||
198 | } | ||
199 | |||
200 | fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> { | ||
201 | Box::new(ty) | ||
202 | } | ||
203 | |||
204 | fn ty_data<'a>(&self, ty: &'a Box<chalk_ir::TyData<Self>>) -> &'a chalk_ir::TyData<Self> { | ||
205 | ty | ||
206 | } | ||
207 | |||
208 | fn intern_lifetime( | ||
209 | &self, | ||
210 | lifetime: chalk_ir::LifetimeData<Self>, | ||
211 | ) -> chalk_ir::LifetimeData<Self> { | ||
212 | lifetime | ||
213 | } | ||
214 | |||
215 | fn lifetime_data<'a>( | ||
216 | &self, | ||
217 | lifetime: &'a chalk_ir::LifetimeData<Self>, | ||
218 | ) -> &'a chalk_ir::LifetimeData<Self> { | ||
219 | lifetime | ||
220 | } | ||
221 | |||
222 | fn intern_const(&self, constant: chalk_ir::ConstData<Self>) -> Arc<chalk_ir::ConstData<Self>> { | ||
223 | Arc::new(constant) | ||
224 | } | ||
225 | |||
226 | fn const_data<'a>( | ||
227 | &self, | ||
228 | constant: &'a Arc<chalk_ir::ConstData<Self>>, | ||
229 | ) -> &'a chalk_ir::ConstData<Self> { | ||
230 | constant | ||
231 | } | ||
232 | |||
233 | fn const_eq(&self, _ty: &Box<chalk_ir::TyData<Self>>, _c1: &(), _c2: &()) -> bool { | ||
234 | true | ||
235 | } | ||
236 | |||
237 | fn intern_generic_arg( | ||
238 | &self, | ||
239 | parameter: chalk_ir::GenericArgData<Self>, | ||
240 | ) -> chalk_ir::GenericArgData<Self> { | ||
241 | parameter | ||
242 | } | ||
243 | |||
244 | fn generic_arg_data<'a>( | ||
245 | &self, | ||
246 | parameter: &'a chalk_ir::GenericArgData<Self>, | ||
247 | ) -> &'a chalk_ir::GenericArgData<Self> { | ||
248 | parameter | ||
249 | } | ||
250 | |||
251 | fn intern_goal(&self, goal: GoalData<Self>) -> Arc<GoalData<Self>> { | ||
252 | Arc::new(goal) | ||
253 | } | ||
254 | |||
255 | fn intern_goals<E>( | ||
256 | &self, | ||
257 | data: impl IntoIterator<Item = Result<Goal<Self>, E>>, | ||
258 | ) -> Result<Self::InternedGoals, E> { | ||
259 | data.into_iter().collect() | ||
260 | } | ||
261 | |||
262 | fn goal_data<'a>(&self, goal: &'a Arc<GoalData<Self>>) -> &'a GoalData<Self> { | ||
263 | goal | ||
264 | } | ||
265 | |||
266 | fn goals_data<'a>(&self, goals: &'a Vec<Goal<Interner>>) -> &'a [Goal<Interner>] { | ||
267 | goals | ||
268 | } | ||
269 | |||
270 | fn intern_substitution<E>( | ||
271 | &self, | ||
272 | data: impl IntoIterator<Item = Result<GenericArg<Self>, E>>, | ||
273 | ) -> Result<Vec<GenericArg<Self>>, E> { | ||
274 | data.into_iter().collect() | ||
275 | } | ||
276 | |||
277 | fn substitution_data<'a>( | ||
278 | &self, | ||
279 | substitution: &'a Vec<GenericArg<Self>>, | ||
280 | ) -> &'a [GenericArg<Self>] { | ||
281 | substitution | ||
282 | } | ||
283 | |||
284 | fn intern_program_clause( | ||
285 | &self, | ||
286 | data: chalk_ir::ProgramClauseData<Self>, | ||
287 | ) -> chalk_ir::ProgramClauseData<Self> { | ||
288 | data | ||
289 | } | ||
290 | |||
291 | fn program_clause_data<'a>( | ||
292 | &self, | ||
293 | clause: &'a chalk_ir::ProgramClauseData<Self>, | ||
294 | ) -> &'a chalk_ir::ProgramClauseData<Self> { | ||
295 | clause | ||
296 | } | ||
297 | |||
298 | fn intern_program_clauses<E>( | ||
299 | &self, | ||
300 | data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>, | ||
301 | ) -> Result<Arc<[chalk_ir::ProgramClause<Self>]>, E> { | ||
302 | data.into_iter().collect() | ||
303 | } | ||
304 | |||
305 | fn program_clauses_data<'a>( | ||
306 | &self, | ||
307 | clauses: &'a Arc<[chalk_ir::ProgramClause<Self>]>, | ||
308 | ) -> &'a [chalk_ir::ProgramClause<Self>] { | ||
309 | &clauses | ||
310 | } | ||
311 | |||
312 | fn intern_quantified_where_clauses<E>( | ||
313 | &self, | ||
314 | data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>, | ||
315 | ) -> Result<Self::InternedQuantifiedWhereClauses, E> { | ||
316 | data.into_iter().collect() | ||
317 | } | ||
318 | |||
319 | fn quantified_where_clauses_data<'a>( | ||
320 | &self, | ||
321 | clauses: &'a Self::InternedQuantifiedWhereClauses, | ||
322 | ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] { | ||
323 | clauses | ||
324 | } | ||
325 | |||
326 | fn intern_generic_arg_kinds<E>( | ||
327 | &self, | ||
328 | data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>, | ||
329 | ) -> Result<Self::InternedVariableKinds, E> { | ||
330 | data.into_iter().collect() | ||
331 | } | ||
332 | |||
333 | fn variable_kinds_data<'a>( | ||
334 | &self, | ||
335 | parameter_kinds: &'a Self::InternedVariableKinds, | ||
336 | ) -> &'a [chalk_ir::VariableKind<Self>] { | ||
337 | ¶meter_kinds | ||
338 | } | ||
339 | |||
340 | fn intern_canonical_var_kinds<E>( | ||
341 | &self, | ||
342 | data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>, | ||
343 | ) -> Result<Self::InternedCanonicalVarKinds, E> { | ||
344 | data.into_iter().collect() | ||
345 | } | ||
346 | |||
347 | fn canonical_var_kinds_data<'a>( | ||
348 | &self, | ||
349 | canonical_var_kinds: &'a Self::InternedCanonicalVarKinds, | ||
350 | ) -> &'a [chalk_ir::CanonicalVarKind<Self>] { | ||
351 | &canonical_var_kinds | ||
352 | } | ||
353 | |||
354 | fn intern_constraints<E>( | ||
355 | &self, | ||
356 | data: impl IntoIterator<Item = Result<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>, E>>, | ||
357 | ) -> Result<Self::InternedConstraints, E> { | ||
358 | data.into_iter().collect() | ||
359 | } | ||
360 | |||
361 | fn constraints_data<'a>( | ||
362 | &self, | ||
363 | constraints: &'a Self::InternedConstraints, | ||
364 | ) -> &'a [chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>] { | ||
365 | constraints | ||
366 | } | ||
367 | fn debug_closure_id( | ||
368 | _fn_def_id: chalk_ir::ClosureId<Self>, | ||
369 | _fmt: &mut fmt::Formatter<'_>, | ||
370 | ) -> Option<fmt::Result> { | ||
371 | None | ||
372 | } | ||
373 | fn debug_constraints( | ||
374 | _clauses: &chalk_ir::Constraints<Self>, | ||
375 | _fmt: &mut fmt::Formatter<'_>, | ||
376 | ) -> Option<fmt::Result> { | ||
377 | None | ||
378 | } | ||
379 | } | ||
380 | |||
381 | impl chalk_ir::interner::HasInterner for Interner { | ||
382 | type Interner = Self; | ||
383 | } | ||
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs new file mode 100644 index 000000000..fe62f3fa7 --- /dev/null +++ b/crates/hir_ty/src/traits/chalk/mapping.rs | |||
@@ -0,0 +1,787 @@ | |||
1 | //! This module contains the implementations of the `ToChalk` trait, which | ||
2 | //! handles conversion between our data types and their corresponding types in | ||
3 | //! Chalk (in both directions); plus some helper functions for more specialized | ||
4 | //! conversions. | ||
5 | |||
6 | use chalk_ir::{ | ||
7 | cast::Cast, fold::shift::Shift, interner::HasInterner, PlaceholderIndex, Scalar, TypeName, | ||
8 | UniverseIndex, | ||
9 | }; | ||
10 | use chalk_solve::rust_ir; | ||
11 | |||
12 | use base_db::salsa::InternKey; | ||
13 | use hir_def::{type_ref::Mutability, AssocContainerId, GenericDefId, Lookup, TypeAliasId}; | ||
14 | |||
15 | use crate::{ | ||
16 | db::HirDatabase, | ||
17 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, | ||
18 | traits::{Canonical, Obligation}, | ||
19 | ApplicationTy, CallableDefId, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId, | ||
20 | ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor, | ||
21 | }; | ||
22 | |||
23 | use super::interner::*; | ||
24 | use super::*; | ||
25 | |||
26 | impl ToChalk for Ty { | ||
27 | type Chalk = chalk_ir::Ty<Interner>; | ||
28 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { | ||
29 | match self { | ||
30 | Ty::Apply(apply_ty) => match apply_ty.ctor { | ||
31 | TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters), | ||
32 | TypeCtor::Array => array_to_chalk(db, apply_ty.parameters), | ||
33 | TypeCtor::FnPtr { num_args: _, is_varargs } => { | ||
34 | let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); | ||
35 | chalk_ir::TyData::Function(chalk_ir::FnPointer { | ||
36 | num_binders: 0, | ||
37 | abi: (), | ||
38 | safety: chalk_ir::Safety::Safe, | ||
39 | variadic: is_varargs, | ||
40 | substitution, | ||
41 | }) | ||
42 | .intern(&Interner) | ||
43 | } | ||
44 | _ => { | ||
45 | let name = apply_ty.ctor.to_chalk(db); | ||
46 | let substitution = apply_ty.parameters.to_chalk(db); | ||
47 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
48 | } | ||
49 | }, | ||
50 | Ty::Projection(proj_ty) => { | ||
51 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); | ||
52 | let substitution = proj_ty.parameters.to_chalk(db); | ||
53 | chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { | ||
54 | associated_ty_id, | ||
55 | substitution, | ||
56 | }) | ||
57 | .cast(&Interner) | ||
58 | .intern(&Interner) | ||
59 | } | ||
60 | Ty::Placeholder(id) => { | ||
61 | let interned_id = db.intern_type_param_id(id); | ||
62 | PlaceholderIndex { | ||
63 | ui: UniverseIndex::ROOT, | ||
64 | idx: interned_id.as_intern_id().as_usize(), | ||
65 | } | ||
66 | .to_ty::<Interner>(&Interner) | ||
67 | } | ||
68 | Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner), | ||
69 | Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), | ||
70 | Ty::Dyn(predicates) => { | ||
71 | let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter( | ||
72 | &Interner, | ||
73 | predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)), | ||
74 | ); | ||
75 | let bounded_ty = chalk_ir::DynTy { | ||
76 | bounds: make_binders(where_clauses, 1), | ||
77 | lifetime: FAKE_PLACEHOLDER.to_lifetime(&Interner), | ||
78 | }; | ||
79 | chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) | ||
80 | } | ||
81 | Ty::Opaque(opaque_ty) => { | ||
82 | let opaque_ty_id = opaque_ty.opaque_ty_id.to_chalk(db); | ||
83 | let substitution = opaque_ty.parameters.to_chalk(db); | ||
84 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { | ||
85 | opaque_ty_id, | ||
86 | substitution, | ||
87 | })) | ||
88 | .intern(&Interner) | ||
89 | } | ||
90 | Ty::Unknown => { | ||
91 | let substitution = chalk_ir::Substitution::empty(&Interner); | ||
92 | let name = TypeName::Error; | ||
93 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self { | ||
98 | match chalk.data(&Interner).clone() { | ||
99 | chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name { | ||
100 | TypeName::Error => Ty::Unknown, | ||
101 | TypeName::Ref(m) => ref_from_chalk(db, m, apply_ty.substitution), | ||
102 | TypeName::Array => array_from_chalk(db, apply_ty.substitution), | ||
103 | _ => { | ||
104 | let ctor = from_chalk(db, apply_ty.name); | ||
105 | let parameters = from_chalk(db, apply_ty.substitution); | ||
106 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
107 | } | ||
108 | }, | ||
109 | chalk_ir::TyData::Placeholder(idx) => { | ||
110 | assert_eq!(idx.ui, UniverseIndex::ROOT); | ||
111 | let interned_id = crate::db::GlobalTypeParamId::from_intern_id( | ||
112 | crate::salsa::InternId::from(idx.idx), | ||
113 | ); | ||
114 | Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) | ||
115 | } | ||
116 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Projection(proj)) => { | ||
117 | let associated_ty = from_chalk(db, proj.associated_ty_id); | ||
118 | let parameters = from_chalk(db, proj.substitution); | ||
119 | Ty::Projection(ProjectionTy { associated_ty, parameters }) | ||
120 | } | ||
121 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => { | ||
122 | let impl_trait_id = from_chalk(db, opaque_ty.opaque_ty_id); | ||
123 | let parameters = from_chalk(db, opaque_ty.substitution); | ||
124 | Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters }) | ||
125 | } | ||
126 | chalk_ir::TyData::Function(chalk_ir::FnPointer { | ||
127 | num_binders, | ||
128 | variadic, | ||
129 | substitution, | ||
130 | .. | ||
131 | }) => { | ||
132 | assert_eq!(num_binders, 0); | ||
133 | let parameters: Substs = from_chalk( | ||
134 | db, | ||
135 | substitution.shifted_out(&Interner).expect("fn ptr should have no binders"), | ||
136 | ); | ||
137 | Ty::Apply(ApplicationTy { | ||
138 | ctor: TypeCtor::FnPtr { | ||
139 | num_args: (parameters.len() - 1) as u16, | ||
140 | is_varargs: variadic, | ||
141 | }, | ||
142 | parameters, | ||
143 | }) | ||
144 | } | ||
145 | chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx), | ||
146 | chalk_ir::TyData::InferenceVar(_iv, _kind) => Ty::Unknown, | ||
147 | chalk_ir::TyData::Dyn(where_clauses) => { | ||
148 | assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); | ||
149 | let predicates = where_clauses | ||
150 | .bounds | ||
151 | .skip_binders() | ||
152 | .iter(&Interner) | ||
153 | .map(|c| from_chalk(db, c.clone())) | ||
154 | .collect(); | ||
155 | Ty::Dyn(predicates) | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | const FAKE_PLACEHOLDER: PlaceholderIndex = | ||
162 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::MAX }; | ||
163 | |||
164 | /// We currently don't model lifetimes, but Chalk does. So, we have to insert a | ||
165 | /// fake lifetime here, because Chalks built-in logic may expect it to be there. | ||
166 | fn ref_to_chalk( | ||
167 | db: &dyn HirDatabase, | ||
168 | mutability: Mutability, | ||
169 | subst: Substs, | ||
170 | ) -> chalk_ir::Ty<Interner> { | ||
171 | let arg = subst[0].clone().to_chalk(db); | ||
172 | let lifetime = FAKE_PLACEHOLDER.to_lifetime(&Interner); | ||
173 | chalk_ir::ApplicationTy { | ||
174 | name: TypeName::Ref(mutability.to_chalk(db)), | ||
175 | substitution: chalk_ir::Substitution::from_iter( | ||
176 | &Interner, | ||
177 | vec![lifetime.cast(&Interner), arg.cast(&Interner)], | ||
178 | ), | ||
179 | } | ||
180 | .intern(&Interner) | ||
181 | } | ||
182 | |||
183 | /// Here we remove the lifetime from the type we got from Chalk. | ||
184 | fn ref_from_chalk( | ||
185 | db: &dyn HirDatabase, | ||
186 | mutability: chalk_ir::Mutability, | ||
187 | subst: chalk_ir::Substitution<Interner>, | ||
188 | ) -> Ty { | ||
189 | let tys = subst | ||
190 | .iter(&Interner) | ||
191 | .filter_map(|p| Some(from_chalk(db, p.ty(&Interner)?.clone()))) | ||
192 | .collect(); | ||
193 | Ty::apply(TypeCtor::Ref(from_chalk(db, mutability)), Substs(tys)) | ||
194 | } | ||
195 | |||
196 | /// We currently don't model constants, but Chalk does. So, we have to insert a | ||
197 | /// fake constant here, because Chalks built-in logic may expect it to be there. | ||
198 | fn array_to_chalk(db: &dyn HirDatabase, subst: Substs) -> chalk_ir::Ty<Interner> { | ||
199 | let arg = subst[0].clone().to_chalk(db); | ||
200 | let usize_ty = chalk_ir::ApplicationTy { | ||
201 | name: TypeName::Scalar(Scalar::Uint(chalk_ir::UintTy::Usize)), | ||
202 | substitution: chalk_ir::Substitution::empty(&Interner), | ||
203 | } | ||
204 | .intern(&Interner); | ||
205 | let const_ = FAKE_PLACEHOLDER.to_const(&Interner, usize_ty); | ||
206 | chalk_ir::ApplicationTy { | ||
207 | name: TypeName::Array, | ||
208 | substitution: chalk_ir::Substitution::from_iter( | ||
209 | &Interner, | ||
210 | vec![arg.cast(&Interner), const_.cast(&Interner)], | ||
211 | ), | ||
212 | } | ||
213 | .intern(&Interner) | ||
214 | } | ||
215 | |||
216 | /// Here we remove the const from the type we got from Chalk. | ||
217 | fn array_from_chalk(db: &dyn HirDatabase, subst: chalk_ir::Substitution<Interner>) -> Ty { | ||
218 | let tys = subst | ||
219 | .iter(&Interner) | ||
220 | .filter_map(|p| Some(from_chalk(db, p.ty(&Interner)?.clone()))) | ||
221 | .collect(); | ||
222 | Ty::apply(TypeCtor::Array, Substs(tys)) | ||
223 | } | ||
224 | |||
225 | impl ToChalk for Substs { | ||
226 | type Chalk = chalk_ir::Substitution<Interner>; | ||
227 | |||
228 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> { | ||
229 | chalk_ir::Substitution::from_iter(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db))) | ||
230 | } | ||
231 | |||
232 | fn from_chalk(db: &dyn HirDatabase, parameters: chalk_ir::Substitution<Interner>) -> Substs { | ||
233 | let tys = parameters | ||
234 | .iter(&Interner) | ||
235 | .map(|p| match p.ty(&Interner) { | ||
236 | Some(ty) => from_chalk(db, ty.clone()), | ||
237 | None => unimplemented!(), | ||
238 | }) | ||
239 | .collect(); | ||
240 | Substs(tys) | ||
241 | } | ||
242 | } | ||
243 | |||
244 | impl ToChalk for TraitRef { | ||
245 | type Chalk = chalk_ir::TraitRef<Interner>; | ||
246 | |||
247 | fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> { | ||
248 | let trait_id = self.trait_.to_chalk(db); | ||
249 | let substitution = self.substs.to_chalk(db); | ||
250 | chalk_ir::TraitRef { trait_id, substitution } | ||
251 | } | ||
252 | |||
253 | fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self { | ||
254 | let trait_ = from_chalk(db, trait_ref.trait_id); | ||
255 | let substs = from_chalk(db, trait_ref.substitution); | ||
256 | TraitRef { trait_, substs } | ||
257 | } | ||
258 | } | ||
259 | |||
260 | impl ToChalk for hir_def::TraitId { | ||
261 | type Chalk = TraitId; | ||
262 | |||
263 | fn to_chalk(self, _db: &dyn HirDatabase) -> TraitId { | ||
264 | chalk_ir::TraitId(self.as_intern_id()) | ||
265 | } | ||
266 | |||
267 | fn from_chalk(_db: &dyn HirDatabase, trait_id: TraitId) -> hir_def::TraitId { | ||
268 | InternKey::from_intern_id(trait_id.0) | ||
269 | } | ||
270 | } | ||
271 | |||
272 | impl ToChalk for OpaqueTyId { | ||
273 | type Chalk = chalk_ir::OpaqueTyId<Interner>; | ||
274 | |||
275 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::OpaqueTyId<Interner> { | ||
276 | db.intern_impl_trait_id(self).into() | ||
277 | } | ||
278 | |||
279 | fn from_chalk( | ||
280 | db: &dyn HirDatabase, | ||
281 | opaque_ty_id: chalk_ir::OpaqueTyId<Interner>, | ||
282 | ) -> OpaqueTyId { | ||
283 | db.lookup_intern_impl_trait_id(opaque_ty_id.into()) | ||
284 | } | ||
285 | } | ||
286 | |||
287 | impl ToChalk for TypeCtor { | ||
288 | type Chalk = TypeName<Interner>; | ||
289 | |||
290 | fn to_chalk(self, db: &dyn HirDatabase) -> TypeName<Interner> { | ||
291 | match self { | ||
292 | TypeCtor::AssociatedType(type_alias) => { | ||
293 | let type_id = type_alias.to_chalk(db); | ||
294 | TypeName::AssociatedType(type_id) | ||
295 | } | ||
296 | |||
297 | TypeCtor::OpaqueType(impl_trait_id) => { | ||
298 | let id = impl_trait_id.to_chalk(db); | ||
299 | TypeName::OpaqueType(id) | ||
300 | } | ||
301 | |||
302 | TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), | ||
303 | TypeCtor::Char => TypeName::Scalar(Scalar::Char), | ||
304 | TypeCtor::Int(int_ty) => TypeName::Scalar(int_ty_to_chalk(int_ty)), | ||
305 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 }) => { | ||
306 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) | ||
307 | } | ||
308 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 }) => { | ||
309 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) | ||
310 | } | ||
311 | |||
312 | TypeCtor::Tuple { cardinality } => TypeName::Tuple(cardinality.into()), | ||
313 | TypeCtor::RawPtr(mutability) => TypeName::Raw(mutability.to_chalk(db)), | ||
314 | TypeCtor::Slice => TypeName::Slice, | ||
315 | TypeCtor::Array => TypeName::Array, | ||
316 | TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)), | ||
317 | TypeCtor::Str => TypeName::Str, | ||
318 | TypeCtor::FnDef(callable_def) => { | ||
319 | let id = callable_def.to_chalk(db); | ||
320 | TypeName::FnDef(id) | ||
321 | } | ||
322 | TypeCtor::Never => TypeName::Never, | ||
323 | |||
324 | TypeCtor::Closure { def, expr } => { | ||
325 | let closure_id = db.intern_closure((def, expr)); | ||
326 | TypeName::Closure(closure_id.into()) | ||
327 | } | ||
328 | |||
329 | TypeCtor::Adt(adt_id) => TypeName::Adt(chalk_ir::AdtId(adt_id)), | ||
330 | |||
331 | TypeCtor::FnPtr { .. } => { | ||
332 | // This should not be reached, since Chalk doesn't represent | ||
333 | // function pointers with TypeName | ||
334 | unreachable!() | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | |||
339 | fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor { | ||
340 | match type_name { | ||
341 | TypeName::Adt(struct_id) => TypeCtor::Adt(struct_id.0), | ||
342 | TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), | ||
343 | TypeName::OpaqueType(opaque_type_id) => { | ||
344 | TypeCtor::OpaqueType(from_chalk(db, opaque_type_id)) | ||
345 | } | ||
346 | |||
347 | TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool, | ||
348 | TypeName::Scalar(Scalar::Char) => TypeCtor::Char, | ||
349 | TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(IntTy { | ||
350 | signedness: Signedness::Signed, | ||
351 | bitness: bitness_from_chalk_int(int_ty), | ||
352 | }), | ||
353 | TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(IntTy { | ||
354 | signedness: Signedness::Unsigned, | ||
355 | bitness: bitness_from_chalk_uint(uint_ty), | ||
356 | }), | ||
357 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => { | ||
358 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 }) | ||
359 | } | ||
360 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => { | ||
361 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 }) | ||
362 | } | ||
363 | TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 }, | ||
364 | TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)), | ||
365 | TypeName::Slice => TypeCtor::Slice, | ||
366 | TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)), | ||
367 | TypeName::Str => TypeCtor::Str, | ||
368 | TypeName::Never => TypeCtor::Never, | ||
369 | |||
370 | TypeName::FnDef(fn_def_id) => { | ||
371 | let callable_def = from_chalk(db, fn_def_id); | ||
372 | TypeCtor::FnDef(callable_def) | ||
373 | } | ||
374 | TypeName::Array => TypeCtor::Array, | ||
375 | |||
376 | TypeName::Closure(id) => { | ||
377 | let id: crate::db::ClosureId = id.into(); | ||
378 | let (def, expr) = db.lookup_intern_closure(id); | ||
379 | TypeCtor::Closure { def, expr } | ||
380 | } | ||
381 | |||
382 | TypeName::Error => { | ||
383 | // this should not be reached, since we don't represent TypeName::Error with TypeCtor | ||
384 | unreachable!() | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | |||
390 | fn bitness_from_chalk_uint(uint_ty: chalk_ir::UintTy) -> IntBitness { | ||
391 | use chalk_ir::UintTy; | ||
392 | |||
393 | match uint_ty { | ||
394 | UintTy::Usize => IntBitness::Xsize, | ||
395 | UintTy::U8 => IntBitness::X8, | ||
396 | UintTy::U16 => IntBitness::X16, | ||
397 | UintTy::U32 => IntBitness::X32, | ||
398 | UintTy::U64 => IntBitness::X64, | ||
399 | UintTy::U128 => IntBitness::X128, | ||
400 | } | ||
401 | } | ||
402 | |||
403 | fn bitness_from_chalk_int(int_ty: chalk_ir::IntTy) -> IntBitness { | ||
404 | use chalk_ir::IntTy; | ||
405 | |||
406 | match int_ty { | ||
407 | IntTy::Isize => IntBitness::Xsize, | ||
408 | IntTy::I8 => IntBitness::X8, | ||
409 | IntTy::I16 => IntBitness::X16, | ||
410 | IntTy::I32 => IntBitness::X32, | ||
411 | IntTy::I64 => IntBitness::X64, | ||
412 | IntTy::I128 => IntBitness::X128, | ||
413 | } | ||
414 | } | ||
415 | |||
416 | fn int_ty_to_chalk(int_ty: IntTy) -> Scalar { | ||
417 | use chalk_ir::{IntTy, UintTy}; | ||
418 | |||
419 | match int_ty.signedness { | ||
420 | Signedness::Signed => Scalar::Int(match int_ty.bitness { | ||
421 | IntBitness::Xsize => IntTy::Isize, | ||
422 | IntBitness::X8 => IntTy::I8, | ||
423 | IntBitness::X16 => IntTy::I16, | ||
424 | IntBitness::X32 => IntTy::I32, | ||
425 | IntBitness::X64 => IntTy::I64, | ||
426 | IntBitness::X128 => IntTy::I128, | ||
427 | }), | ||
428 | Signedness::Unsigned => Scalar::Uint(match int_ty.bitness { | ||
429 | IntBitness::Xsize => UintTy::Usize, | ||
430 | IntBitness::X8 => UintTy::U8, | ||
431 | IntBitness::X16 => UintTy::U16, | ||
432 | IntBitness::X32 => UintTy::U32, | ||
433 | IntBitness::X64 => UintTy::U64, | ||
434 | IntBitness::X128 => UintTy::U128, | ||
435 | }), | ||
436 | } | ||
437 | } | ||
438 | |||
439 | impl ToChalk for Mutability { | ||
440 | type Chalk = chalk_ir::Mutability; | ||
441 | fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk { | ||
442 | match self { | ||
443 | Mutability::Shared => chalk_ir::Mutability::Not, | ||
444 | Mutability::Mut => chalk_ir::Mutability::Mut, | ||
445 | } | ||
446 | } | ||
447 | fn from_chalk(_db: &dyn HirDatabase, chalk: Self::Chalk) -> Self { | ||
448 | match chalk { | ||
449 | chalk_ir::Mutability::Mut => Mutability::Mut, | ||
450 | chalk_ir::Mutability::Not => Mutability::Shared, | ||
451 | } | ||
452 | } | ||
453 | } | ||
454 | |||
455 | impl ToChalk for hir_def::ImplId { | ||
456 | type Chalk = ImplId; | ||
457 | |||
458 | fn to_chalk(self, _db: &dyn HirDatabase) -> ImplId { | ||
459 | chalk_ir::ImplId(self.as_intern_id()) | ||
460 | } | ||
461 | |||
462 | fn from_chalk(_db: &dyn HirDatabase, impl_id: ImplId) -> hir_def::ImplId { | ||
463 | InternKey::from_intern_id(impl_id.0) | ||
464 | } | ||
465 | } | ||
466 | |||
467 | impl ToChalk for CallableDefId { | ||
468 | type Chalk = FnDefId; | ||
469 | |||
470 | fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId { | ||
471 | db.intern_callable_def(self).into() | ||
472 | } | ||
473 | |||
474 | fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId { | ||
475 | db.lookup_intern_callable_def(fn_def_id.into()) | ||
476 | } | ||
477 | } | ||
478 | |||
479 | impl ToChalk for TypeAliasId { | ||
480 | type Chalk = AssocTypeId; | ||
481 | |||
482 | fn to_chalk(self, _db: &dyn HirDatabase) -> AssocTypeId { | ||
483 | chalk_ir::AssocTypeId(self.as_intern_id()) | ||
484 | } | ||
485 | |||
486 | fn from_chalk(_db: &dyn HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId { | ||
487 | InternKey::from_intern_id(type_alias_id.0) | ||
488 | } | ||
489 | } | ||
490 | |||
491 | pub struct TypeAliasAsValue(pub TypeAliasId); | ||
492 | |||
493 | impl ToChalk for TypeAliasAsValue { | ||
494 | type Chalk = AssociatedTyValueId; | ||
495 | |||
496 | fn to_chalk(self, _db: &dyn HirDatabase) -> AssociatedTyValueId { | ||
497 | rust_ir::AssociatedTyValueId(self.0.as_intern_id()) | ||
498 | } | ||
499 | |||
500 | fn from_chalk( | ||
501 | _db: &dyn HirDatabase, | ||
502 | assoc_ty_value_id: AssociatedTyValueId, | ||
503 | ) -> TypeAliasAsValue { | ||
504 | TypeAliasAsValue(TypeAliasId::from_intern_id(assoc_ty_value_id.0)) | ||
505 | } | ||
506 | } | ||
507 | |||
508 | impl ToChalk for GenericPredicate { | ||
509 | type Chalk = chalk_ir::QuantifiedWhereClause<Interner>; | ||
510 | |||
511 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> { | ||
512 | match self { | ||
513 | GenericPredicate::Implemented(trait_ref) => { | ||
514 | let chalk_trait_ref = trait_ref.to_chalk(db); | ||
515 | let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner); | ||
516 | make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0) | ||
517 | } | ||
518 | GenericPredicate::Projection(projection_pred) => { | ||
519 | let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner); | ||
520 | let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner); | ||
521 | let alias = chalk_ir::AliasTy::Projection(projection); | ||
522 | make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0) | ||
523 | } | ||
524 | GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), | ||
525 | } | ||
526 | } | ||
527 | |||
528 | fn from_chalk( | ||
529 | db: &dyn HirDatabase, | ||
530 | where_clause: chalk_ir::QuantifiedWhereClause<Interner>, | ||
531 | ) -> GenericPredicate { | ||
532 | // we don't produce any where clauses with binders and can't currently deal with them | ||
533 | match where_clause | ||
534 | .skip_binders() | ||
535 | .shifted_out(&Interner) | ||
536 | .expect("unexpected bound vars in where clause") | ||
537 | { | ||
538 | chalk_ir::WhereClause::Implemented(tr) => { | ||
539 | GenericPredicate::Implemented(from_chalk(db, tr)) | ||
540 | } | ||
541 | chalk_ir::WhereClause::AliasEq(projection_eq) => { | ||
542 | let projection_ty = from_chalk( | ||
543 | db, | ||
544 | match projection_eq.alias { | ||
545 | chalk_ir::AliasTy::Projection(p) => p, | ||
546 | _ => unimplemented!(), | ||
547 | }, | ||
548 | ); | ||
549 | let ty = from_chalk(db, projection_eq.ty); | ||
550 | GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty }) | ||
551 | } | ||
552 | |||
553 | chalk_ir::WhereClause::LifetimeOutlives(_) => { | ||
554 | // we shouldn't get these from Chalk | ||
555 | panic!("encountered LifetimeOutlives from Chalk") | ||
556 | } | ||
557 | |||
558 | chalk_ir::WhereClause::TypeOutlives(_) => { | ||
559 | // we shouldn't get these from Chalk | ||
560 | panic!("encountered TypeOutlives from Chalk") | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | } | ||
565 | |||
566 | impl ToChalk for ProjectionTy { | ||
567 | type Chalk = chalk_ir::ProjectionTy<Interner>; | ||
568 | |||
569 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> { | ||
570 | chalk_ir::ProjectionTy { | ||
571 | associated_ty_id: self.associated_ty.to_chalk(db), | ||
572 | substitution: self.parameters.to_chalk(db), | ||
573 | } | ||
574 | } | ||
575 | |||
576 | fn from_chalk( | ||
577 | db: &dyn HirDatabase, | ||
578 | projection_ty: chalk_ir::ProjectionTy<Interner>, | ||
579 | ) -> ProjectionTy { | ||
580 | ProjectionTy { | ||
581 | associated_ty: from_chalk(db, projection_ty.associated_ty_id), | ||
582 | parameters: from_chalk(db, projection_ty.substitution), | ||
583 | } | ||
584 | } | ||
585 | } | ||
586 | |||
587 | impl ToChalk for ProjectionPredicate { | ||
588 | type Chalk = chalk_ir::AliasEq<Interner>; | ||
589 | |||
590 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> { | ||
591 | chalk_ir::AliasEq { | ||
592 | alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)), | ||
593 | ty: self.ty.to_chalk(db), | ||
594 | } | ||
595 | } | ||
596 | |||
597 | fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self { | ||
598 | unimplemented!() | ||
599 | } | ||
600 | } | ||
601 | |||
602 | impl ToChalk for Obligation { | ||
603 | type Chalk = chalk_ir::DomainGoal<Interner>; | ||
604 | |||
605 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> { | ||
606 | match self { | ||
607 | Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner), | ||
608 | Obligation::Projection(pr) => pr.to_chalk(db).cast(&Interner), | ||
609 | } | ||
610 | } | ||
611 | |||
612 | fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self { | ||
613 | unimplemented!() | ||
614 | } | ||
615 | } | ||
616 | |||
617 | impl<T> ToChalk for Canonical<T> | ||
618 | where | ||
619 | T: ToChalk, | ||
620 | T::Chalk: HasInterner<Interner = Interner>, | ||
621 | { | ||
622 | type Chalk = chalk_ir::Canonical<T::Chalk>; | ||
623 | |||
624 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { | ||
625 | let kinds = self | ||
626 | .kinds | ||
627 | .iter() | ||
628 | .map(|k| match k { | ||
629 | TyKind::General => chalk_ir::TyKind::General, | ||
630 | TyKind::Integer => chalk_ir::TyKind::Integer, | ||
631 | TyKind::Float => chalk_ir::TyKind::Float, | ||
632 | }) | ||
633 | .map(|tk| { | ||
634 | chalk_ir::CanonicalVarKind::new( | ||
635 | chalk_ir::VariableKind::Ty(tk), | ||
636 | chalk_ir::UniverseIndex::ROOT, | ||
637 | ) | ||
638 | }); | ||
639 | let value = self.value.to_chalk(db); | ||
640 | chalk_ir::Canonical { | ||
641 | value, | ||
642 | binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds), | ||
643 | } | ||
644 | } | ||
645 | |||
646 | fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { | ||
647 | let kinds = canonical | ||
648 | .binders | ||
649 | .iter(&Interner) | ||
650 | .map(|k| match k.kind { | ||
651 | chalk_ir::VariableKind::Ty(tk) => match tk { | ||
652 | chalk_ir::TyKind::General => TyKind::General, | ||
653 | chalk_ir::TyKind::Integer => TyKind::Integer, | ||
654 | chalk_ir::TyKind::Float => TyKind::Float, | ||
655 | }, | ||
656 | chalk_ir::VariableKind::Lifetime => panic!("unexpected lifetime from Chalk"), | ||
657 | chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"), | ||
658 | }) | ||
659 | .collect(); | ||
660 | Canonical { kinds, value: from_chalk(db, canonical.value) } | ||
661 | } | ||
662 | } | ||
663 | |||
664 | impl ToChalk for Arc<TraitEnvironment> { | ||
665 | type Chalk = chalk_ir::Environment<Interner>; | ||
666 | |||
667 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Environment<Interner> { | ||
668 | let mut clauses = Vec::new(); | ||
669 | for pred in &self.predicates { | ||
670 | if pred.is_error() { | ||
671 | // for env, we just ignore errors | ||
672 | continue; | ||
673 | } | ||
674 | let program_clause: chalk_ir::ProgramClause<Interner> = | ||
675 | pred.clone().to_chalk(db).cast(&Interner); | ||
676 | clauses.push(program_clause.into_from_env_clause(&Interner)); | ||
677 | } | ||
678 | chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses) | ||
679 | } | ||
680 | |||
681 | fn from_chalk( | ||
682 | _db: &dyn HirDatabase, | ||
683 | _env: chalk_ir::Environment<Interner>, | ||
684 | ) -> Arc<TraitEnvironment> { | ||
685 | unimplemented!() | ||
686 | } | ||
687 | } | ||
688 | |||
689 | impl<T: ToChalk> ToChalk for InEnvironment<T> | ||
690 | where | ||
691 | T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>, | ||
692 | { | ||
693 | type Chalk = chalk_ir::InEnvironment<T::Chalk>; | ||
694 | |||
695 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { | ||
696 | chalk_ir::InEnvironment { | ||
697 | environment: self.environment.to_chalk(db), | ||
698 | goal: self.value.to_chalk(db), | ||
699 | } | ||
700 | } | ||
701 | |||
702 | fn from_chalk( | ||
703 | db: &dyn HirDatabase, | ||
704 | in_env: chalk_ir::InEnvironment<T::Chalk>, | ||
705 | ) -> InEnvironment<T> { | ||
706 | InEnvironment { | ||
707 | environment: from_chalk(db, in_env.environment), | ||
708 | value: from_chalk(db, in_env.goal), | ||
709 | } | ||
710 | } | ||
711 | } | ||
712 | |||
713 | pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> | ||
714 | where | ||
715 | T: HasInterner<Interner = Interner>, | ||
716 | { | ||
717 | chalk_ir::Binders::new( | ||
718 | chalk_ir::VariableKinds::from_iter( | ||
719 | &Interner, | ||
720 | std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General)).take(num_vars), | ||
721 | ), | ||
722 | value, | ||
723 | ) | ||
724 | } | ||
725 | |||
726 | pub(super) fn convert_where_clauses( | ||
727 | db: &dyn HirDatabase, | ||
728 | def: GenericDefId, | ||
729 | substs: &Substs, | ||
730 | ) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> { | ||
731 | let generic_predicates = db.generic_predicates(def); | ||
732 | let mut result = Vec::with_capacity(generic_predicates.len()); | ||
733 | for pred in generic_predicates.iter() { | ||
734 | if pred.value.is_error() { | ||
735 | // skip errored predicates completely | ||
736 | continue; | ||
737 | } | ||
738 | result.push(pred.clone().subst(substs).to_chalk(db)); | ||
739 | } | ||
740 | result | ||
741 | } | ||
742 | |||
743 | pub(super) fn generic_predicate_to_inline_bound( | ||
744 | db: &dyn HirDatabase, | ||
745 | pred: &GenericPredicate, | ||
746 | self_ty: &Ty, | ||
747 | ) -> Option<rust_ir::InlineBound<Interner>> { | ||
748 | // An InlineBound is like a GenericPredicate, except the self type is left out. | ||
749 | // We don't have a special type for this, but Chalk does. | ||
750 | match pred { | ||
751 | GenericPredicate::Implemented(trait_ref) => { | ||
752 | if &trait_ref.substs[0] != self_ty { | ||
753 | // we can only convert predicates back to type bounds if they | ||
754 | // have the expected self type | ||
755 | return None; | ||
756 | } | ||
757 | let args_no_self = trait_ref.substs[1..] | ||
758 | .iter() | ||
759 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
760 | .collect(); | ||
761 | let trait_bound = | ||
762 | rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; | ||
763 | Some(rust_ir::InlineBound::TraitBound(trait_bound)) | ||
764 | } | ||
765 | GenericPredicate::Projection(proj) => { | ||
766 | if &proj.projection_ty.parameters[0] != self_ty { | ||
767 | return None; | ||
768 | } | ||
769 | let trait_ = match proj.projection_ty.associated_ty.lookup(db.upcast()).container { | ||
770 | AssocContainerId::TraitId(t) => t, | ||
771 | _ => panic!("associated type not in trait"), | ||
772 | }; | ||
773 | let args_no_self = proj.projection_ty.parameters[1..] | ||
774 | .iter() | ||
775 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
776 | .collect(); | ||
777 | let alias_eq_bound = rust_ir::AliasEqBound { | ||
778 | value: proj.ty.clone().to_chalk(db), | ||
779 | trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self }, | ||
780 | associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db), | ||
781 | parameters: Vec::new(), // FIXME we don't support generic associated types yet | ||
782 | }; | ||
783 | Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) | ||
784 | } | ||
785 | GenericPredicate::Error => None, | ||
786 | } | ||
787 | } | ||
diff --git a/crates/hir_ty/src/traits/chalk/tls.rs b/crates/hir_ty/src/traits/chalk/tls.rs new file mode 100644 index 000000000..db915625c --- /dev/null +++ b/crates/hir_ty/src/traits/chalk/tls.rs | |||
@@ -0,0 +1,358 @@ | |||
1 | //! Implementation of Chalk debug helper functions using TLS. | ||
2 | use std::fmt; | ||
3 | |||
4 | use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication, TypeName}; | ||
5 | use itertools::Itertools; | ||
6 | |||
7 | use super::{from_chalk, Interner}; | ||
8 | use crate::{db::HirDatabase, CallableDefId, TypeCtor}; | ||
9 | use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId}; | ||
10 | |||
11 | pub use unsafe_tls::{set_current_program, with_current_program}; | ||
12 | |||
13 | pub struct DebugContext<'a>(&'a dyn HirDatabase); | ||
14 | |||
15 | impl DebugContext<'_> { | ||
16 | pub fn debug_struct_id( | ||
17 | &self, | ||
18 | id: super::AdtId, | ||
19 | f: &mut fmt::Formatter<'_>, | ||
20 | ) -> Result<(), fmt::Error> { | ||
21 | let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Adt(id)); | ||
22 | match type_ctor { | ||
23 | TypeCtor::Bool => write!(f, "bool")?, | ||
24 | TypeCtor::Char => write!(f, "char")?, | ||
25 | TypeCtor::Int(t) => write!(f, "{}", t)?, | ||
26 | TypeCtor::Float(t) => write!(f, "{}", t)?, | ||
27 | TypeCtor::Str => write!(f, "str")?, | ||
28 | TypeCtor::Slice => write!(f, "slice")?, | ||
29 | TypeCtor::Array => write!(f, "array")?, | ||
30 | TypeCtor::RawPtr(m) => write!(f, "*{}", m.as_keyword_for_ptr())?, | ||
31 | TypeCtor::Ref(m) => write!(f, "&{}", m.as_keyword_for_ref())?, | ||
32 | TypeCtor::Never => write!(f, "!")?, | ||
33 | TypeCtor::Tuple { .. } => { | ||
34 | write!(f, "()")?; | ||
35 | } | ||
36 | TypeCtor::FnPtr { .. } => { | ||
37 | write!(f, "fn")?; | ||
38 | } | ||
39 | TypeCtor::FnDef(def) => { | ||
40 | let name = match def { | ||
41 | CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(), | ||
42 | CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(), | ||
43 | CallableDefId::EnumVariantId(e) => { | ||
44 | let enum_data = self.0.enum_data(e.parent); | ||
45 | enum_data.variants[e.local_id].name.clone() | ||
46 | } | ||
47 | }; | ||
48 | match def { | ||
49 | CallableDefId::FunctionId(_) => write!(f, "{{fn {}}}", name)?, | ||
50 | CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => { | ||
51 | write!(f, "{{ctor {}}}", name)? | ||
52 | } | ||
53 | } | ||
54 | } | ||
55 | TypeCtor::Adt(def_id) => { | ||
56 | let name = match def_id { | ||
57 | AdtId::StructId(it) => self.0.struct_data(it).name.clone(), | ||
58 | AdtId::UnionId(it) => self.0.union_data(it).name.clone(), | ||
59 | AdtId::EnumId(it) => self.0.enum_data(it).name.clone(), | ||
60 | }; | ||
61 | write!(f, "{}", name)?; | ||
62 | } | ||
63 | TypeCtor::AssociatedType(type_alias) => { | ||
64 | let trait_ = match type_alias.lookup(self.0.upcast()).container { | ||
65 | AssocContainerId::TraitId(it) => it, | ||
66 | _ => panic!("not an associated type"), | ||
67 | }; | ||
68 | let trait_name = self.0.trait_data(trait_).name.clone(); | ||
69 | let name = self.0.type_alias_data(type_alias).name.clone(); | ||
70 | write!(f, "{}::{}", trait_name, name)?; | ||
71 | } | ||
72 | TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id { | ||
73 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | ||
74 | write!(f, "{{impl trait {} of {:?}}}", idx, func)?; | ||
75 | } | ||
76 | }, | ||
77 | TypeCtor::Closure { def, expr } => { | ||
78 | write!(f, "{{closure {:?} in ", expr.into_raw())?; | ||
79 | match def { | ||
80 | DefWithBodyId::FunctionId(func) => { | ||
81 | write!(f, "fn {}", self.0.function_data(func).name)? | ||
82 | } | ||
83 | DefWithBodyId::StaticId(s) => { | ||
84 | if let Some(name) = self.0.static_data(s).name.as_ref() { | ||
85 | write!(f, "body of static {}", name)?; | ||
86 | } else { | ||
87 | write!(f, "body of unnamed static {:?}", s)?; | ||
88 | } | ||
89 | } | ||
90 | DefWithBodyId::ConstId(c) => { | ||
91 | if let Some(name) = self.0.const_data(c).name.as_ref() { | ||
92 | write!(f, "body of const {}", name)?; | ||
93 | } else { | ||
94 | write!(f, "body of unnamed const {:?}", c)?; | ||
95 | } | ||
96 | } | ||
97 | }; | ||
98 | write!(f, "}}")?; | ||
99 | } | ||
100 | } | ||
101 | Ok(()) | ||
102 | } | ||
103 | |||
104 | pub fn debug_trait_id( | ||
105 | &self, | ||
106 | id: super::TraitId, | ||
107 | fmt: &mut fmt::Formatter<'_>, | ||
108 | ) -> Result<(), fmt::Error> { | ||
109 | let trait_: hir_def::TraitId = from_chalk(self.0, id); | ||
110 | let trait_data = self.0.trait_data(trait_); | ||
111 | write!(fmt, "{}", trait_data.name) | ||
112 | } | ||
113 | |||
114 | pub fn debug_assoc_type_id( | ||
115 | &self, | ||
116 | id: super::AssocTypeId, | ||
117 | fmt: &mut fmt::Formatter<'_>, | ||
118 | ) -> Result<(), fmt::Error> { | ||
119 | let type_alias: TypeAliasId = from_chalk(self.0, id); | ||
120 | let type_alias_data = self.0.type_alias_data(type_alias); | ||
121 | let trait_ = match type_alias.lookup(self.0.upcast()).container { | ||
122 | AssocContainerId::TraitId(t) => t, | ||
123 | _ => panic!("associated type not in trait"), | ||
124 | }; | ||
125 | let trait_data = self.0.trait_data(trait_); | ||
126 | write!(fmt, "{}::{}", trait_data.name, type_alias_data.name) | ||
127 | } | ||
128 | |||
129 | pub fn debug_opaque_ty_id( | ||
130 | &self, | ||
131 | opaque_ty_id: chalk_ir::OpaqueTyId<Interner>, | ||
132 | fmt: &mut fmt::Formatter<'_>, | ||
133 | ) -> Result<(), fmt::Error> { | ||
134 | fmt.debug_struct("OpaqueTyId").field("index", &opaque_ty_id.0).finish() | ||
135 | } | ||
136 | |||
137 | pub fn debug_alias( | ||
138 | &self, | ||
139 | alias_ty: &AliasTy<Interner>, | ||
140 | fmt: &mut fmt::Formatter<'_>, | ||
141 | ) -> Result<(), fmt::Error> { | ||
142 | match alias_ty { | ||
143 | AliasTy::Projection(projection_ty) => self.debug_projection_ty(projection_ty, fmt), | ||
144 | AliasTy::Opaque(opaque_ty) => self.debug_opaque_ty(opaque_ty, fmt), | ||
145 | } | ||
146 | } | ||
147 | |||
148 | pub fn debug_projection_ty( | ||
149 | &self, | ||
150 | projection_ty: &chalk_ir::ProjectionTy<Interner>, | ||
151 | fmt: &mut fmt::Formatter<'_>, | ||
152 | ) -> Result<(), fmt::Error> { | ||
153 | let type_alias: TypeAliasId = from_chalk(self.0, projection_ty.associated_ty_id); | ||
154 | let type_alias_data = self.0.type_alias_data(type_alias); | ||
155 | let trait_ = match type_alias.lookup(self.0.upcast()).container { | ||
156 | AssocContainerId::TraitId(t) => t, | ||
157 | _ => panic!("associated type not in trait"), | ||
158 | }; | ||
159 | let trait_data = self.0.trait_data(trait_); | ||
160 | let params = projection_ty.substitution.as_slice(&Interner); | ||
161 | write!(fmt, "<{:?} as {}", ¶ms[0], trait_data.name,)?; | ||
162 | if params.len() > 1 { | ||
163 | write!( | ||
164 | fmt, | ||
165 | "<{}>", | ||
166 | ¶ms[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))), | ||
167 | )?; | ||
168 | } | ||
169 | write!(fmt, ">::{}", type_alias_data.name) | ||
170 | } | ||
171 | |||
172 | pub fn debug_opaque_ty( | ||
173 | &self, | ||
174 | opaque_ty: &chalk_ir::OpaqueTy<Interner>, | ||
175 | fmt: &mut fmt::Formatter<'_>, | ||
176 | ) -> Result<(), fmt::Error> { | ||
177 | write!(fmt, "{:?}", opaque_ty.opaque_ty_id) | ||
178 | } | ||
179 | |||
180 | pub fn debug_ty( | ||
181 | &self, | ||
182 | ty: &chalk_ir::Ty<Interner>, | ||
183 | fmt: &mut fmt::Formatter<'_>, | ||
184 | ) -> Result<(), fmt::Error> { | ||
185 | write!(fmt, "{:?}", ty.data(&Interner)) | ||
186 | } | ||
187 | |||
188 | pub fn debug_lifetime( | ||
189 | &self, | ||
190 | lifetime: &Lifetime<Interner>, | ||
191 | fmt: &mut fmt::Formatter<'_>, | ||
192 | ) -> Result<(), fmt::Error> { | ||
193 | write!(fmt, "{:?}", lifetime.data(&Interner)) | ||
194 | } | ||
195 | |||
196 | pub fn debug_generic_arg( | ||
197 | &self, | ||
198 | parameter: &GenericArg<Interner>, | ||
199 | fmt: &mut fmt::Formatter<'_>, | ||
200 | ) -> Result<(), fmt::Error> { | ||
201 | write!(fmt, "{:?}", parameter.data(&Interner).inner_debug()) | ||
202 | } | ||
203 | |||
204 | pub fn debug_goal( | ||
205 | &self, | ||
206 | goal: &Goal<Interner>, | ||
207 | fmt: &mut fmt::Formatter<'_>, | ||
208 | ) -> Result<(), fmt::Error> { | ||
209 | let goal_data = goal.data(&Interner); | ||
210 | write!(fmt, "{:?}", goal_data) | ||
211 | } | ||
212 | |||
213 | pub fn debug_goals( | ||
214 | &self, | ||
215 | goals: &Goals<Interner>, | ||
216 | fmt: &mut fmt::Formatter<'_>, | ||
217 | ) -> Result<(), fmt::Error> { | ||
218 | write!(fmt, "{:?}", goals.debug(&Interner)) | ||
219 | } | ||
220 | |||
221 | pub fn debug_program_clause_implication( | ||
222 | &self, | ||
223 | pci: &ProgramClauseImplication<Interner>, | ||
224 | fmt: &mut fmt::Formatter<'_>, | ||
225 | ) -> Result<(), fmt::Error> { | ||
226 | write!(fmt, "{:?}", pci.debug(&Interner)) | ||
227 | } | ||
228 | |||
229 | pub fn debug_application_ty( | ||
230 | &self, | ||
231 | application_ty: &chalk_ir::ApplicationTy<Interner>, | ||
232 | fmt: &mut fmt::Formatter<'_>, | ||
233 | ) -> Result<(), fmt::Error> { | ||
234 | write!(fmt, "{:?}", application_ty.debug(&Interner)) | ||
235 | } | ||
236 | |||
237 | pub fn debug_substitution( | ||
238 | &self, | ||
239 | substitution: &chalk_ir::Substitution<Interner>, | ||
240 | fmt: &mut fmt::Formatter<'_>, | ||
241 | ) -> Result<(), fmt::Error> { | ||
242 | write!(fmt, "{:?}", substitution.debug(&Interner)) | ||
243 | } | ||
244 | |||
245 | pub fn debug_separator_trait_ref( | ||
246 | &self, | ||
247 | separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>, | ||
248 | fmt: &mut fmt::Formatter<'_>, | ||
249 | ) -> Result<(), fmt::Error> { | ||
250 | write!(fmt, "{:?}", separator_trait_ref.debug(&Interner)) | ||
251 | } | ||
252 | |||
253 | pub fn debug_fn_def_id( | ||
254 | &self, | ||
255 | fn_def_id: chalk_ir::FnDefId<Interner>, | ||
256 | fmt: &mut fmt::Formatter<'_>, | ||
257 | ) -> Result<(), fmt::Error> { | ||
258 | let def: CallableDefId = from_chalk(self.0, fn_def_id); | ||
259 | let name = match def { | ||
260 | CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(), | ||
261 | CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(), | ||
262 | CallableDefId::EnumVariantId(e) => { | ||
263 | let enum_data = self.0.enum_data(e.parent); | ||
264 | enum_data.variants[e.local_id].name.clone() | ||
265 | } | ||
266 | }; | ||
267 | match def { | ||
268 | CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name), | ||
269 | CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => { | ||
270 | write!(fmt, "{{ctor {}}}", name) | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
275 | pub fn debug_const( | ||
276 | &self, | ||
277 | _constant: &chalk_ir::Const<Interner>, | ||
278 | fmt: &mut fmt::Formatter<'_>, | ||
279 | ) -> fmt::Result { | ||
280 | write!(fmt, "const") | ||
281 | } | ||
282 | |||
283 | pub fn debug_variable_kinds( | ||
284 | &self, | ||
285 | variable_kinds: &chalk_ir::VariableKinds<Interner>, | ||
286 | fmt: &mut fmt::Formatter<'_>, | ||
287 | ) -> fmt::Result { | ||
288 | write!(fmt, "{:?}", variable_kinds.as_slice(&Interner)) | ||
289 | } | ||
290 | pub fn debug_variable_kinds_with_angles( | ||
291 | &self, | ||
292 | variable_kinds: &chalk_ir::VariableKinds<Interner>, | ||
293 | fmt: &mut fmt::Formatter<'_>, | ||
294 | ) -> fmt::Result { | ||
295 | write!(fmt, "{:?}", variable_kinds.inner_debug(&Interner)) | ||
296 | } | ||
297 | pub fn debug_canonical_var_kinds( | ||
298 | &self, | ||
299 | canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Interner>, | ||
300 | fmt: &mut fmt::Formatter<'_>, | ||
301 | ) -> fmt::Result { | ||
302 | write!(fmt, "{:?}", canonical_var_kinds.as_slice(&Interner)) | ||
303 | } | ||
304 | pub fn debug_program_clause( | ||
305 | &self, | ||
306 | clause: &chalk_ir::ProgramClause<Interner>, | ||
307 | fmt: &mut fmt::Formatter<'_>, | ||
308 | ) -> fmt::Result { | ||
309 | write!(fmt, "{:?}", clause.data(&Interner)) | ||
310 | } | ||
311 | pub fn debug_program_clauses( | ||
312 | &self, | ||
313 | clauses: &chalk_ir::ProgramClauses<Interner>, | ||
314 | fmt: &mut fmt::Formatter<'_>, | ||
315 | ) -> fmt::Result { | ||
316 | write!(fmt, "{:?}", clauses.as_slice(&Interner)) | ||
317 | } | ||
318 | pub fn debug_quantified_where_clauses( | ||
319 | &self, | ||
320 | clauses: &chalk_ir::QuantifiedWhereClauses<Interner>, | ||
321 | fmt: &mut fmt::Formatter<'_>, | ||
322 | ) -> fmt::Result { | ||
323 | write!(fmt, "{:?}", clauses.as_slice(&Interner)) | ||
324 | } | ||
325 | } | ||
326 | |||
327 | mod unsafe_tls { | ||
328 | use super::DebugContext; | ||
329 | use crate::db::HirDatabase; | ||
330 | use scoped_tls::scoped_thread_local; | ||
331 | |||
332 | scoped_thread_local!(static PROGRAM: DebugContext); | ||
333 | |||
334 | pub fn with_current_program<R>( | ||
335 | op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R, | ||
336 | ) -> R { | ||
337 | if PROGRAM.is_set() { | ||
338 | PROGRAM.with(|prog| op(Some(prog))) | ||
339 | } else { | ||
340 | op(None) | ||
341 | } | ||
342 | } | ||
343 | |||
344 | pub fn set_current_program<OP, R>(p: &dyn HirDatabase, op: OP) -> R | ||
345 | where | ||
346 | OP: FnOnce() -> R, | ||
347 | { | ||
348 | let ctx = DebugContext(p); | ||
349 | // we're transmuting the lifetime in the DebugContext to static. This is | ||
350 | // fine because we only keep the reference for the lifetime of this | ||
351 | // function, *and* the only way to access the context is through | ||
352 | // `with_current_program`, which hides the lifetime through the `for` | ||
353 | // type. | ||
354 | let static_p: &DebugContext<'static> = | ||
355 | unsafe { std::mem::transmute::<&DebugContext, &DebugContext<'static>>(&ctx) }; | ||
356 | PROGRAM.set(static_p, || op()) | ||
357 | } | ||
358 | } | ||
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs new file mode 100644 index 000000000..e3e244268 --- /dev/null +++ b/crates/hir_ty/src/utils.rs | |||
@@ -0,0 +1,257 @@ | |||
1 | //! Helper functions for working with def, which don't need to be a separate | ||
2 | //! query, but can't be computed directly from `*Data` (ie, which need a `db`). | ||
3 | use std::sync::Arc; | ||
4 | |||
5 | use hir_def::generics::WherePredicateTarget; | ||
6 | use hir_def::{ | ||
7 | adt::VariantData, | ||
8 | db::DefDatabase, | ||
9 | generics::{GenericParams, TypeParamData, TypeParamProvenance}, | ||
10 | path::Path, | ||
11 | resolver::{HasResolver, TypeNs}, | ||
12 | type_ref::TypeRef, | ||
13 | AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, | ||
14 | }; | ||
15 | use hir_expand::name::{name, Name}; | ||
16 | |||
17 | use crate::{db::HirDatabase, GenericPredicate, TraitRef}; | ||
18 | |||
19 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | ||
20 | let resolver = trait_.resolver(db); | ||
21 | // returning the iterator directly doesn't easily work because of | ||
22 | // lifetime problems, but since there usually shouldn't be more than a | ||
23 | // few direct traits this should be fine (we could even use some kind of | ||
24 | // SmallVec if performance is a concern) | ||
25 | let generic_params = db.generic_params(trait_.into()); | ||
26 | let trait_self = generic_params.find_trait_self_param(); | ||
27 | generic_params | ||
28 | .where_predicates | ||
29 | .iter() | ||
30 | .filter_map(|pred| match &pred.target { | ||
31 | WherePredicateTarget::TypeRef(TypeRef::Path(p)) if p == &Path::from(name![Self]) => { | ||
32 | pred.bound.as_path() | ||
33 | } | ||
34 | WherePredicateTarget::TypeParam(local_id) if Some(*local_id) == trait_self => { | ||
35 | pred.bound.as_path() | ||
36 | } | ||
37 | _ => None, | ||
38 | }) | ||
39 | .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { | ||
40 | Some(TypeNs::TraitId(t)) => Some(t), | ||
41 | _ => None, | ||
42 | }) | ||
43 | .collect() | ||
44 | } | ||
45 | |||
46 | fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<TraitRef> { | ||
47 | // returning the iterator directly doesn't easily work because of | ||
48 | // lifetime problems, but since there usually shouldn't be more than a | ||
49 | // few direct traits this should be fine (we could even use some kind of | ||
50 | // SmallVec if performance is a concern) | ||
51 | let generic_params = db.generic_params(trait_ref.trait_.into()); | ||
52 | let trait_self = match generic_params.find_trait_self_param() { | ||
53 | Some(p) => TypeParamId { parent: trait_ref.trait_.into(), local_id: p }, | ||
54 | None => return Vec::new(), | ||
55 | }; | ||
56 | db.generic_predicates_for_param(trait_self) | ||
57 | .iter() | ||
58 | .filter_map(|pred| { | ||
59 | pred.as_ref().filter_map(|pred| match pred { | ||
60 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | ||
61 | _ => None, | ||
62 | }) | ||
63 | }) | ||
64 | .map(|pred| pred.subst(&trait_ref.substs)) | ||
65 | .collect() | ||
66 | } | ||
67 | |||
68 | /// Returns an iterator over the whole super trait hierarchy (including the | ||
69 | /// trait itself). | ||
70 | pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | ||
71 | // we need to take care a bit here to avoid infinite loops in case of cycles | ||
72 | // (i.e. if we have `trait A: B; trait B: A;`) | ||
73 | let mut result = vec![trait_]; | ||
74 | let mut i = 0; | ||
75 | while i < result.len() { | ||
76 | let t = result[i]; | ||
77 | // yeah this is quadratic, but trait hierarchies should be flat | ||
78 | // enough that this doesn't matter | ||
79 | for tt in direct_super_traits(db, t) { | ||
80 | if !result.contains(&tt) { | ||
81 | result.push(tt); | ||
82 | } | ||
83 | } | ||
84 | i += 1; | ||
85 | } | ||
86 | result | ||
87 | } | ||
88 | |||
89 | /// Given a trait ref (`Self: Trait`), builds all the implied trait refs for | ||
90 | /// super traits. The original trait ref will be included. So the difference to | ||
91 | /// `all_super_traits` is that we keep track of type parameters; for example if | ||
92 | /// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get | ||
93 | /// `Self: OtherTrait<i32>`. | ||
94 | pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> Vec<TraitRef> { | ||
95 | // we need to take care a bit here to avoid infinite loops in case of cycles | ||
96 | // (i.e. if we have `trait A: B; trait B: A;`) | ||
97 | let mut result = vec![trait_ref]; | ||
98 | let mut i = 0; | ||
99 | while i < result.len() { | ||
100 | let t = &result[i]; | ||
101 | // yeah this is quadratic, but trait hierarchies should be flat | ||
102 | // enough that this doesn't matter | ||
103 | for tt in direct_super_trait_refs(db, t) { | ||
104 | if !result.iter().any(|tr| tr.trait_ == tt.trait_) { | ||
105 | result.push(tt); | ||
106 | } | ||
107 | } | ||
108 | i += 1; | ||
109 | } | ||
110 | result | ||
111 | } | ||
112 | |||
113 | pub(super) fn associated_type_by_name_including_super_traits( | ||
114 | db: &dyn HirDatabase, | ||
115 | trait_ref: TraitRef, | ||
116 | name: &Name, | ||
117 | ) -> Option<(TraitRef, TypeAliasId)> { | ||
118 | all_super_trait_refs(db, trait_ref).into_iter().find_map(|t| { | ||
119 | let assoc_type = db.trait_data(t.trait_).associated_type_by_name(name)?; | ||
120 | Some((t, assoc_type)) | ||
121 | }) | ||
122 | } | ||
123 | |||
124 | pub(super) fn variant_data(db: &dyn DefDatabase, var: VariantId) -> Arc<VariantData> { | ||
125 | match var { | ||
126 | VariantId::StructId(it) => db.struct_data(it).variant_data.clone(), | ||
127 | VariantId::UnionId(it) => db.union_data(it).variant_data.clone(), | ||
128 | VariantId::EnumVariantId(it) => { | ||
129 | db.enum_data(it.parent).variants[it.local_id].variant_data.clone() | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | /// Helper for mutating `Arc<[T]>` (i.e. `Arc::make_mut` for Arc slices). | ||
135 | /// The underlying values are cloned if there are other strong references. | ||
136 | pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] { | ||
137 | if Arc::get_mut(a).is_none() { | ||
138 | *a = a.iter().cloned().collect(); | ||
139 | } | ||
140 | Arc::get_mut(a).unwrap() | ||
141 | } | ||
142 | |||
143 | pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { | ||
144 | let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); | ||
145 | Generics { def, params: db.generic_params(def), parent_generics } | ||
146 | } | ||
147 | |||
148 | #[derive(Debug)] | ||
149 | pub(crate) struct Generics { | ||
150 | def: GenericDefId, | ||
151 | pub(crate) params: Arc<GenericParams>, | ||
152 | parent_generics: Option<Box<Generics>>, | ||
153 | } | ||
154 | |||
155 | impl Generics { | ||
156 | pub(crate) fn iter<'a>( | ||
157 | &'a self, | ||
158 | ) -> impl Iterator<Item = (TypeParamId, &'a TypeParamData)> + 'a { | ||
159 | self.parent_generics | ||
160 | .as_ref() | ||
161 | .into_iter() | ||
162 | .flat_map(|it| { | ||
163 | it.params | ||
164 | .types | ||
165 | .iter() | ||
166 | .map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p)) | ||
167 | }) | ||
168 | .chain( | ||
169 | self.params | ||
170 | .types | ||
171 | .iter() | ||
172 | .map(move |(local_id, p)| (TypeParamId { parent: self.def, local_id }, p)), | ||
173 | ) | ||
174 | } | ||
175 | |||
176 | pub(crate) fn iter_parent<'a>( | ||
177 | &'a self, | ||
178 | ) -> impl Iterator<Item = (TypeParamId, &'a TypeParamData)> + 'a { | ||
179 | self.parent_generics.as_ref().into_iter().flat_map(|it| { | ||
180 | it.params | ||
181 | .types | ||
182 | .iter() | ||
183 | .map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p)) | ||
184 | }) | ||
185 | } | ||
186 | |||
187 | pub(crate) fn len(&self) -> usize { | ||
188 | self.len_split().0 | ||
189 | } | ||
190 | |||
191 | /// (total, parents, child) | ||
192 | pub(crate) fn len_split(&self) -> (usize, usize, usize) { | ||
193 | let parent = self.parent_generics.as_ref().map_or(0, |p| p.len()); | ||
194 | let child = self.params.types.len(); | ||
195 | (parent + child, parent, child) | ||
196 | } | ||
197 | |||
198 | /// (parent total, self param, type param list, impl trait) | ||
199 | pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize) { | ||
200 | let parent = self.parent_generics.as_ref().map_or(0, |p| p.len()); | ||
201 | let self_params = self | ||
202 | .params | ||
203 | .types | ||
204 | .iter() | ||
205 | .filter(|(_, p)| p.provenance == TypeParamProvenance::TraitSelf) | ||
206 | .count(); | ||
207 | let list_params = self | ||
208 | .params | ||
209 | .types | ||
210 | .iter() | ||
211 | .filter(|(_, p)| p.provenance == TypeParamProvenance::TypeParamList) | ||
212 | .count(); | ||
213 | let impl_trait_params = self | ||
214 | .params | ||
215 | .types | ||
216 | .iter() | ||
217 | .filter(|(_, p)| p.provenance == TypeParamProvenance::ArgumentImplTrait) | ||
218 | .count(); | ||
219 | (parent, self_params, list_params, impl_trait_params) | ||
220 | } | ||
221 | |||
222 | pub(crate) fn param_idx(&self, param: TypeParamId) -> Option<usize> { | ||
223 | Some(self.find_param(param)?.0) | ||
224 | } | ||
225 | |||
226 | fn find_param(&self, param: TypeParamId) -> Option<(usize, &TypeParamData)> { | ||
227 | if param.parent == self.def { | ||
228 | let (idx, (_local_id, data)) = self | ||
229 | .params | ||
230 | .types | ||
231 | .iter() | ||
232 | .enumerate() | ||
233 | .find(|(_, (idx, _))| *idx == param.local_id) | ||
234 | .unwrap(); | ||
235 | let (_total, parent_len, _child) = self.len_split(); | ||
236 | Some((parent_len + idx, data)) | ||
237 | } else { | ||
238 | self.parent_generics.as_ref().and_then(|g| g.find_param(param)) | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | |||
243 | fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> { | ||
244 | let container = match def { | ||
245 | GenericDefId::FunctionId(it) => it.lookup(db).container, | ||
246 | GenericDefId::TypeAliasId(it) => it.lookup(db).container, | ||
247 | GenericDefId::ConstId(it) => it.lookup(db).container, | ||
248 | GenericDefId::EnumVariantId(it) => return Some(it.parent.into()), | ||
249 | GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None, | ||
250 | }; | ||
251 | |||
252 | match container { | ||
253 | AssocContainerId::ImplId(it) => Some(it.into()), | ||
254 | AssocContainerId::TraitId(it) => Some(it.into()), | ||
255 | AssocContainerId::ContainerId(_) => None, | ||
256 | } | ||
257 | } | ||