aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/lib.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-02-09 11:35:08 +0000
committerGitHub <[email protected]>2020-02-09 11:35:08 +0000
commit01836a0f35fa163025c64cabe1d0c34bb4f69c92 (patch)
treeaa1a3cf97173b2885f8b6d23002c73196f9a0b61 /crates/ra_hir_ty/src/lib.rs
parent961a69b88f923d4477ca4f746a793217a0cc8576 (diff)
parenteefe02ce6e1750b771cf99125429358e87485745 (diff)
Merge #3050
3050: Refactor type parameters, implement argument position impl trait r=matklad a=flodiebold I wanted to implement APIT by lowering to type parameters because we need to do that anyway for correctness and don't need Chalk support for it; this grew into some more wide-ranging refactoring of how type parameters are handled :sweat_smile: - use Ty::Bound instead of Ty::Param to represent polymorphism, and explicitly count binders. This gets us closer to Chalk's way of doing things, and means that we now only use Param as a placeholder for an unknown type, e.g. within a generic function. I.e. we're never using Param in a situation where we want to substitute it, and the method to do that is gone; `subst` now always works on bound variables. (This changes how the types of generic functions print; previously, you'd get something like `fn identity<i32>(T) -> T`, but now we display the substituted signature `fn identity<i32>(i32) -> i32`, which I think makes more sense.) - once we do this, it's more natural to represent `Param` by a globally unique ID; the use of indices was mostly to make substituting easier. This also means we fix the bug where `Param` loses its name when going through Chalk. - I would actually like to rename `Param` to `Placeholder` to better reflect its use and get closer to Chalk, but I'll leave that to a follow-up. - introduce a context for type lowering, to allow lowering `impl Trait` to different things depending on where we are. And since we have that, we can also lower type parameters directly to variables instead of placeholders. Also, we'll be able to use this later to collect diagnostics. - implement argument position impl trait by lowering it to type parameters. I've realized that this is necessary to correctly implement it; e.g. consider `fn foo(impl Display) -> impl Something`. It's observable that the return type of e.g. `foo(1u32)` unifies with itself, but doesn't unify with e.g. `foo(1i32)`; so the return type needs to be parameterized by the argument type. This fixes a few bugs as well: - type parameters 'losing' their name when they go through Chalk, as mentioned above (i.e. getting `[missing name]` somewhere) - impl trait not being considered as implementing the super traits (very noticeable for the `db` in RA) - the fact that argument impl trait was only turned into variables when the function got called caused type mismatches when the function was used as a value (fixes a few type mismatches in RA) The one thing I'm not so happy with here is how we're lowering `impl Trait` types to variables; since `TypeRef`s don't have an identity currently, we just count how many of them we have seen while going through the function signature. That's quite fragile though, since we have to do it while desugaring generics and while lowering the type signature, and in the exact same order in both cases. We could consider either giving only `TypeRef::ImplTrait` a local id, or maybe just giving all `TypeRef`s an identity after all (we talked about this before)... Follow-up tasks: - handle return position impl trait; we basically need to create a variable and some trait obligations for that variable - rename `Param` to `Placeholder` Co-authored-by: Florian Diebold <[email protected]> Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir_ty/src/lib.rs')
-rw-r--r--crates/ra_hir_ty/src/lib.rs262
1 files changed, 154 insertions, 108 deletions
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 08d501ccd..c5fe18c85 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -44,8 +44,8 @@ use std::sync::Arc;
44use std::{fmt, iter, mem}; 44use std::{fmt, iter, mem};
45 45
46use hir_def::{ 46use hir_def::{
47 expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, 47 expr::ExprId, generics::TypeParamProvenance, type_ref::Mutability, AdtId, AssocContainerId,
48 HasModule, Lookup, TraitId, TypeAliasId, 48 DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, TypeParamId,
49}; 49};
50use hir_expand::name::Name; 50use hir_expand::name::Name;
51use ra_db::{impl_intern_key, salsa, CrateId}; 51use ra_db::{impl_intern_key, salsa, CrateId};
@@ -60,7 +60,9 @@ use display::{HirDisplay, HirFormatter};
60pub use autoderef::autoderef; 60pub use autoderef::autoderef;
61pub use infer::{do_infer_query, InferTy, InferenceResult}; 61pub use infer::{do_infer_query, InferTy, InferenceResult};
62pub use lower::CallableDef; 62pub use lower::CallableDef;
63pub use lower::{callable_item_sig, TyDefId, ValueTyDefId}; 63pub use lower::{
64 callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId,
65};
64pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 66pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
65 67
66/// A type constructor or type name: this might be something like the primitive 68/// A type constructor or type name: this might be something like the primitive
@@ -285,22 +287,20 @@ pub enum Ty {
285 /// trait and all its parameters are fully known. 287 /// trait and all its parameters are fully known.
286 Projection(ProjectionTy), 288 Projection(ProjectionTy),
287 289
288 /// A type parameter; for example, `T` in `fn f<T>(x: T) {} 290 /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
289 Param { 291 /// {}` when we're type-checking the body of that function. In this
290 /// The index of the parameter (starting with parameters from the 292 /// situation, we know this stands for *some* type, but don't know the exact
291 /// surrounding impl, then the current function). 293 /// type.
292 idx: u32, 294 Param(TypeParamId),
293 /// The name of the parameter, for displaying. 295
294 // FIXME get rid of this 296 /// A bound type variable. This is used in various places: when representing
295 name: Name, 297 /// some polymorphic type like the type of function `fn f<T>`, the type
296 }, 298 /// parameters get turned into variables; during trait resolution, inference
297 299 /// variables get turned into bound variables and back; and in `Dyn` the
298 /// A bound type variable. Used during trait resolution to represent Chalk 300 /// `Self` type is represented with a bound variable as well.
299 /// variables, and in `Dyn` and `Opaque` bounds to represent the `Self` type.
300 Bound(u32), 301 Bound(u32),
301 302
302 /// A type variable used during type checking. Not to be confused with a 303 /// A type variable used during type checking.
303 /// type parameter.
304 Infer(InferTy), 304 Infer(InferTy),
305 305
306 /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust). 306 /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
@@ -364,15 +364,19 @@ impl Substs {
364 } 364 }
365 365
366 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). 366 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
367 pub(crate) fn identity(generic_params: &Generics) -> Substs { 367 pub(crate) fn type_params_for_generics(generic_params: &Generics) -> Substs {
368 Substs( 368 Substs(generic_params.iter().map(|(id, _)| Ty::Param(id)).collect())
369 generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone() }).collect(), 369 }
370 ) 370
371 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
372 pub fn type_params(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> Substs {
373 let params = generics(db, def.into());
374 Substs::type_params_for_generics(&params)
371 } 375 }
372 376
373 /// Return Substs that replace each parameter by a bound variable. 377 /// Return Substs that replace each parameter by a bound variable.
374 pub(crate) fn bound_vars(generic_params: &Generics) -> Substs { 378 pub(crate) fn bound_vars(generic_params: &Generics) -> Substs {
375 Substs(generic_params.iter().map(|(idx, _p)| Ty::Bound(idx)).collect()) 379 Substs(generic_params.iter().enumerate().map(|(idx, _)| Ty::Bound(idx as u32)).collect())
376 } 380 }
377 381
378 pub fn build_for_def(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder { 382 pub fn build_for_def(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder {
@@ -420,11 +424,6 @@ impl SubstsBuilder {
420 self.fill((starting_from..).map(Ty::Bound)) 424 self.fill((starting_from..).map(Ty::Bound))
421 } 425 }
422 426
423 pub fn fill_with_params(self) -> Self {
424 let start = self.vec.len() as u32;
425 self.fill((start..).map(|idx| Ty::Param { idx, name: Name::missing() }))
426 }
427
428 pub fn fill_with_unknown(self) -> Self { 427 pub fn fill_with_unknown(self) -> Self {
429 self.fill(iter::repeat(Ty::Unknown)) 428 self.fill(iter::repeat(Ty::Unknown))
430 } 429 }
@@ -451,6 +450,32 @@ impl Deref for Substs {
451 } 450 }
452} 451}
453 452
453#[derive(Copy, Clone, PartialEq, Eq, Debug)]
454pub struct Binders<T> {
455 pub num_binders: usize,
456 pub value: T,
457}
458
459impl<T> Binders<T> {
460 pub fn new(num_binders: usize, value: T) -> Self {
461 Self { num_binders, value }
462 }
463}
464
465impl<T: TypeWalk> Binders<T> {
466 /// Substitutes all variables.
467 pub fn subst(self, subst: &Substs) -> T {
468 assert_eq!(subst.len(), self.num_binders);
469 self.value.subst_bound_vars(subst)
470 }
471
472 /// Substitutes just a prefix of the variables (shifting the rest).
473 pub fn subst_prefix(self, subst: &Substs) -> Binders<T> {
474 assert!(subst.len() < self.num_binders);
475 Binders::new(self.num_binders - subst.len(), self.value.subst_bound_vars(subst))
476 }
477}
478
454/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. 479/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
455/// Name to be bikeshedded: TraitBound? TraitImplements? 480/// Name to be bikeshedded: TraitBound? TraitImplements?
456#[derive(Clone, PartialEq, Eq, Debug, Hash)] 481#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -551,6 +576,9 @@ pub struct FnSig {
551 params_and_return: Arc<[Ty]>, 576 params_and_return: Arc<[Ty]>,
552} 577}
553 578
579/// A polymorphic function signature.
580pub type PolyFnSig = Binders<FnSig>;
581
554impl FnSig { 582impl FnSig {
555 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig { 583 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig {
556 params.push(ret); 584 params.push(ret);
@@ -730,22 +758,7 @@ pub trait TypeWalk {
730 self 758 self
731 } 759 }
732 760
733 /// Replaces type parameters in this type using the given `Substs`. (So e.g. 761 /// Substitutes `Ty::Bound` vars with the given substitution.
734 /// if `self` is `&[T]`, where type parameter T has index 0, and the
735 /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.)
736 fn subst(self, substs: &Substs) -> Self
737 where
738 Self: Sized,
739 {
740 self.fold(&mut |ty| match ty {
741 Ty::Param { idx, name } => {
742 substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name })
743 }
744 ty => ty,
745 })
746 }
747
748 /// Substitutes `Ty::Bound` vars (as opposed to type parameters).
749 fn subst_bound_vars(mut self, substs: &Substs) -> Self 762 fn subst_bound_vars(mut self, substs: &Substs) -> Self
750 where 763 where
751 Self: Sized, 764 Self: Sized,
@@ -755,6 +768,9 @@ pub trait TypeWalk {
755 &mut Ty::Bound(idx) => { 768 &mut Ty::Bound(idx) => {
756 if idx as usize >= binders && (idx as usize - binders) < substs.len() { 769 if idx as usize >= binders && (idx as usize - binders) < substs.len() {
757 *ty = substs.0[idx as usize - binders].clone(); 770 *ty = substs.0[idx as usize - binders].clone();
771 } else if idx as usize >= binders + substs.len() {
772 // shift free binders
773 *ty = Ty::Bound(idx - substs.len() as u32);
758 } 774 }
759 } 775 }
760 _ => {} 776 _ => {}
@@ -880,7 +896,7 @@ impl HirDisplay for ApplicationTy {
880 write!(f, ") -> {}", sig.ret().display(f.db))?; 896 write!(f, ") -> {}", sig.ret().display(f.db))?;
881 } 897 }
882 TypeCtor::FnDef(def) => { 898 TypeCtor::FnDef(def) => {
883 let sig = f.db.callable_item_signature(def); 899 let sig = f.db.callable_item_signature(def).subst(&self.parameters);
884 let name = match def { 900 let name = match def {
885 CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(), 901 CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(),
886 CallableDef::StructId(s) => f.db.struct_data(s).name.clone(), 902 CallableDef::StructId(s) => f.db.struct_data(s).name.clone(),
@@ -896,9 +912,16 @@ impl HirDisplay for ApplicationTy {
896 } 912 }
897 } 913 }
898 if self.parameters.len() > 0 { 914 if self.parameters.len() > 0 {
899 write!(f, "<")?; 915 let generics = generics(f.db, def.into());
900 f.write_joined(&*self.parameters.0, ", ")?; 916 let (parent_params, self_param, type_params, _impl_trait_params) =
901 write!(f, ">")?; 917 generics.provenance_split();
918 let total_len = parent_params + self_param + type_params;
919 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
920 if total_len > 0 {
921 write!(f, "<")?;
922 f.write_joined(&self.parameters.0[..total_len], ", ")?;
923 write!(f, ">")?;
924 }
902 } 925 }
903 write!(f, "(")?; 926 write!(f, "(")?;
904 f.write_joined(sig.params(), ", ")?; 927 f.write_joined(sig.params(), ", ")?;
@@ -1009,7 +1032,24 @@ impl HirDisplay for Ty {
1009 match self { 1032 match self {
1010 Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, 1033 Ty::Apply(a_ty) => a_ty.hir_fmt(f)?,
1011 Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, 1034 Ty::Projection(p_ty) => p_ty.hir_fmt(f)?,
1012 Ty::Param { name, .. } => write!(f, "{}", name)?, 1035 Ty::Param(id) => {
1036 let generics = generics(f.db, id.parent);
1037 let param_data = &generics.params.types[id.local_id];
1038 match param_data.provenance {
1039 TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
1040 write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
1041 }
1042 TypeParamProvenance::ArgumentImplTrait => {
1043 write!(f, "impl ")?;
1044 let bounds = f.db.generic_predicates_for_param(*id);
1045 let substs = Substs::type_params_for_generics(&generics);
1046 write_bounds_like_dyn_trait(
1047 &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(),
1048 f,
1049 )?;
1050 }
1051 }
1052 }
1013 Ty::Bound(idx) => write!(f, "?{}", idx)?, 1053 Ty::Bound(idx) => write!(f, "?{}", idx)?,
1014 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 1054 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
1015 match self { 1055 match self {
@@ -1017,66 +1057,7 @@ impl HirDisplay for Ty {
1017 Ty::Opaque(_) => write!(f, "impl ")?, 1057 Ty::Opaque(_) => write!(f, "impl ")?,
1018 _ => unreachable!(), 1058 _ => unreachable!(),
1019 }; 1059 };
1020 // Note: This code is written to produce nice results (i.e. 1060 write_bounds_like_dyn_trait(&predicates, f)?;
1021 // corresponding to surface Rust) for types that can occur in
1022 // actual Rust. It will have weird results if the predicates
1023 // aren't as expected (i.e. self types = $0, projection
1024 // predicates for a certain trait come after the Implemented
1025 // predicate for that trait).
1026 let mut first = true;
1027 let mut angle_open = false;
1028 for p in predicates.iter() {
1029 match p {
1030 GenericPredicate::Implemented(trait_ref) => {
1031 if angle_open {
1032 write!(f, ">")?;
1033 }
1034 if !first {
1035 write!(f, " + ")?;
1036 }
1037 // We assume that the self type is $0 (i.e. the
1038 // existential) here, which is the only thing that's
1039 // possible in actual Rust, and hence don't print it
1040 write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?;
1041 if trait_ref.substs.len() > 1 {
1042 write!(f, "<")?;
1043 f.write_joined(&trait_ref.substs[1..], ", ")?;
1044 // there might be assoc type bindings, so we leave the angle brackets open
1045 angle_open = true;
1046 }
1047 }
1048 GenericPredicate::Projection(projection_pred) => {
1049 // in types in actual Rust, these will always come
1050 // after the corresponding Implemented predicate
1051 if angle_open {
1052 write!(f, ", ")?;
1053 } else {
1054 write!(f, "<")?;
1055 angle_open = true;
1056 }
1057 let name =
1058 f.db.type_alias_data(projection_pred.projection_ty.associated_ty)
1059 .name
1060 .clone();
1061 write!(f, "{} = ", name)?;
1062 projection_pred.ty.hir_fmt(f)?;
1063 }
1064 GenericPredicate::Error => {
1065 if angle_open {
1066 // impl Trait<X, {error}>
1067 write!(f, ", ")?;
1068 } else if !first {
1069 // impl Trait + {error}
1070 write!(f, " + ")?;
1071 }
1072 p.hir_fmt(f)?;
1073 }
1074 }
1075 first = false;
1076 }
1077 if angle_open {
1078 write!(f, ">")?;
1079 }
1080 } 1061 }
1081 Ty::Unknown => write!(f, "{{unknown}}")?, 1062 Ty::Unknown => write!(f, "{{unknown}}")?,
1082 Ty::Infer(..) => write!(f, "_")?, 1063 Ty::Infer(..) => write!(f, "_")?,
@@ -1085,6 +1066,71 @@ impl HirDisplay for Ty {
1085 } 1066 }
1086} 1067}
1087 1068
1069fn write_bounds_like_dyn_trait(
1070 predicates: &[GenericPredicate],
1071 f: &mut HirFormatter<impl HirDatabase>,
1072) -> fmt::Result {
1073 // Note: This code is written to produce nice results (i.e.
1074 // corresponding to surface Rust) for types that can occur in
1075 // actual Rust. It will have weird results if the predicates
1076 // aren't as expected (i.e. self types = $0, projection
1077 // predicates for a certain trait come after the Implemented
1078 // predicate for that trait).
1079 let mut first = true;
1080 let mut angle_open = false;
1081 for p in predicates.iter() {
1082 match p {
1083 GenericPredicate::Implemented(trait_ref) => {
1084 if angle_open {
1085 write!(f, ">")?;
1086 }
1087 if !first {
1088 write!(f, " + ")?;
1089 }
1090 // We assume that the self type is $0 (i.e. the
1091 // existential) here, which is the only thing that's
1092 // possible in actual Rust, and hence don't print it
1093 write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?;
1094 if trait_ref.substs.len() > 1 {
1095 write!(f, "<")?;
1096 f.write_joined(&trait_ref.substs[1..], ", ")?;
1097 // there might be assoc type bindings, so we leave the angle brackets open
1098 angle_open = true;
1099 }
1100 }
1101 GenericPredicate::Projection(projection_pred) => {
1102 // in types in actual Rust, these will always come
1103 // after the corresponding Implemented predicate
1104 if angle_open {
1105 write!(f, ", ")?;
1106 } else {
1107 write!(f, "<")?;
1108 angle_open = true;
1109 }
1110 let name =
1111 f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone();
1112 write!(f, "{} = ", name)?;
1113 projection_pred.ty.hir_fmt(f)?;
1114 }
1115 GenericPredicate::Error => {
1116 if angle_open {
1117 // impl Trait<X, {error}>
1118 write!(f, ", ")?;
1119 } else if !first {
1120 // impl Trait + {error}
1121 write!(f, " + ")?;
1122 }
1123 p.hir_fmt(f)?;
1124 }
1125 }
1126 first = false;
1127 }
1128 if angle_open {
1129 write!(f, ">")?;
1130 }
1131 Ok(())
1132}
1133
1088impl TraitRef { 1134impl TraitRef {
1089 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result { 1135 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result {
1090 if f.should_truncate() { 1136 if f.should_truncate() {