From a324d066cb767876f9f3398f83db9f5a8dda8ce4 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 14 Feb 2020 14:44:00 +0100 Subject: Rename Ty::Param => Ty::Placeholder This aligns more with Chalk. --- crates/ra_hir_ty/src/lib.rs | 10 +++++----- crates/ra_hir_ty/src/lower.rs | 8 ++++---- crates/ra_hir_ty/src/traits/chalk.rs | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index c5fe18c85..69ad13952 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -291,7 +291,7 @@ pub enum Ty { /// {}` when we're type-checking the body of that function. In this /// situation, we know this stands for *some* type, but don't know the exact /// type. - Param(TypeParamId), + Placeholder(TypeParamId), /// A bound type variable. This is used in various places: when representing /// some polymorphic type like the type of function `fn f`, the type @@ -365,7 +365,7 @@ impl Substs { /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). pub(crate) fn type_params_for_generics(generic_params: &Generics) -> Substs { - Substs(generic_params.iter().map(|(id, _)| Ty::Param(id)).collect()) + Substs(generic_params.iter().map(|(id, _)| Ty::Placeholder(id)).collect()) } /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). @@ -813,7 +813,7 @@ impl TypeWalk for Ty { p.walk(f); } } - Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} + Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} } f(self); } @@ -831,7 +831,7 @@ impl TypeWalk for Ty { p.walk_mut_binders(f, binders + 1); } } - Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} + Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} } f(self, binders); } @@ -1032,7 +1032,7 @@ impl HirDisplay for Ty { match self { Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, - Ty::Param(id) => { + Ty::Placeholder(id) => { let generics = generics(f.db, id.parent); let param_data = &generics.params.types[id.local_id]; match param_data.provenance { diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index c68c5852b..df24c16a3 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -152,7 +152,7 @@ impl Ty { data.provenance == TypeParamProvenance::ArgumentImplTrait }) .nth(idx as usize) - .map_or(Ty::Unknown, |(id, _)| Ty::Param(id)); + .map_or(Ty::Unknown, |(id, _)| Ty::Placeholder(id)); param } else { Ty::Unknown @@ -270,7 +270,7 @@ impl Ty { let generics = generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => Ty::Param(param_id), + TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), TypeParamLoweringMode::Variable => { let idx = generics.param_idx(param_id).expect("matching generics"); Ty::Bound(idx) @@ -339,7 +339,7 @@ impl Ty { None => return Ty::Unknown, // this can't actually happen }; let param_id = match self_ty { - Ty::Param(id) if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => id, + Ty::Placeholder(id) if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => id, Ty::Bound(idx) if ctx.type_param_mode == TypeParamLoweringMode::Variable => { let generics = generics(ctx.db, def); let param_id = if let Some((id, _)) = generics.iter().nth(idx as usize) { @@ -544,7 +544,7 @@ impl GenericPredicate { let generics = generics(ctx.db, generic_def); let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id }; match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => Ty::Param(param_id), + TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), TypeParamLoweringMode::Variable => { let idx = generics.param_idx(param_id).expect("matching generics"); Ty::Bound(idx) diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 4974c565b..882160fa8 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -142,7 +142,7 @@ impl ToChalk for Ty { let substitution = proj_ty.parameters.to_chalk(db); chalk_ir::AliasTy { associated_ty_id, substitution }.cast().intern() } - Ty::Param(id) => { + Ty::Placeholder(id) => { let interned_id = db.intern_type_param_id(id); PlaceholderIndex { ui: UniverseIndex::ROOT, @@ -184,7 +184,7 @@ impl ToChalk for Ty { let interned_id = crate::db::GlobalTypeParamId::from_intern_id( crate::salsa::InternId::from(idx.idx), ); - Ty::Param(db.lookup_intern_type_param_id(interned_id)) + Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) } chalk_ir::TyData::Alias(proj) => { let associated_ty = from_chalk(db, proj.associated_ty_id); -- cgit v1.2.3 From 5028b86cb8ed40d8b43ba2a1b1cd01377e363626 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 14 Feb 2020 15:01:25 +0100 Subject: Move hir_fmt code to display module --- crates/ra_hir_ty/src/display.rs | 373 ++++++++++++++++++++++++++++++++++++++- crates/ra_hir_ty/src/lib.rs | 375 +--------------------------------------- 2 files changed, 376 insertions(+), 372 deletions(-) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs index d1ff85f0f..14e089cf4 100644 --- a/crates/ra_hir_ty/src/display.rs +++ b/crates/ra_hir_ty/src/display.rs @@ -2,7 +2,12 @@ use std::fmt; -use crate::db::HirDatabase; +use crate::{ + db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, + Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, +}; +use hir_def::{generics::TypeParamProvenance, AdtId, AssocContainerId, Lookup}; +use hir_expand::name::Name; pub struct HirFormatter<'a, 'b, DB> { pub db: &'a DB, @@ -97,3 +102,369 @@ where }) } } + +const TYPE_HINT_TRUNCATION: &str = "…"; + +impl HirDisplay for &Ty { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + HirDisplay::hir_fmt(*self, f) + } +} + +impl HirDisplay for ApplicationTy { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + if f.should_truncate() { + return write!(f, "{}", TYPE_HINT_TRUNCATION); + } + + match self.ctor { + TypeCtor::Bool => write!(f, "bool")?, + TypeCtor::Char => write!(f, "char")?, + TypeCtor::Int(t) => write!(f, "{}", t)?, + TypeCtor::Float(t) => write!(f, "{}", t)?, + TypeCtor::Str => write!(f, "str")?, + TypeCtor::Slice => { + let t = self.parameters.as_single(); + write!(f, "[{}]", t.display(f.db))?; + } + TypeCtor::Array => { + let t = self.parameters.as_single(); + write!(f, "[{}; _]", t.display(f.db))?; + } + TypeCtor::RawPtr(m) => { + let t = self.parameters.as_single(); + write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?; + } + TypeCtor::Ref(m) => { + let t = self.parameters.as_single(); + let ty_display = if f.omit_verbose_types() { + t.display_truncated(f.db, f.max_size) + } else { + t.display(f.db) + }; + write!(f, "&{}{}", m.as_keyword_for_ref(), ty_display)?; + } + TypeCtor::Never => write!(f, "!")?, + TypeCtor::Tuple { .. } => { + let ts = &self.parameters; + if ts.len() == 1 { + write!(f, "({},)", ts[0].display(f.db))?; + } else { + write!(f, "(")?; + f.write_joined(&*ts.0, ", ")?; + write!(f, ")")?; + } + } + TypeCtor::FnPtr { .. } => { + let sig = FnSig::from_fn_ptr_substs(&self.parameters); + write!(f, "fn(")?; + f.write_joined(sig.params(), ", ")?; + write!(f, ") -> {}", sig.ret().display(f.db))?; + } + TypeCtor::FnDef(def) => { + let sig = f.db.callable_item_signature(def).subst(&self.parameters); + let name = match def { + CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(), + CallableDef::StructId(s) => f.db.struct_data(s).name.clone(), + CallableDef::EnumVariantId(e) => { + let enum_data = f.db.enum_data(e.parent); + enum_data.variants[e.local_id].name.clone() + } + }; + match def { + CallableDef::FunctionId(_) => write!(f, "fn {}", name)?, + CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { + write!(f, "{}", name)? + } + } + if self.parameters.len() > 0 { + let generics = generics(f.db, def.into()); + let (parent_params, self_param, type_params, _impl_trait_params) = + generics.provenance_split(); + let total_len = parent_params + self_param + type_params; + // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? + if total_len > 0 { + write!(f, "<")?; + f.write_joined(&self.parameters.0[..total_len], ", ")?; + write!(f, ">")?; + } + } + write!(f, "(")?; + f.write_joined(sig.params(), ", ")?; + write!(f, ") -> {}", sig.ret().display(f.db))?; + } + TypeCtor::Adt(def_id) => { + let name = match def_id { + AdtId::StructId(it) => f.db.struct_data(it).name.clone(), + AdtId::UnionId(it) => f.db.union_data(it).name.clone(), + AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), + }; + write!(f, "{}", name)?; + if self.parameters.len() > 0 { + write!(f, "<")?; + + let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); + let parameters_to_write = if f.omit_verbose_types() { + match self + .ctor + .as_generic_def() + .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) + .filter(|defaults| !defaults.is_empty()) + { + Option::None => self.parameters.0.as_ref(), + Option::Some(default_parameters) => { + for (i, parameter) in self.parameters.iter().enumerate() { + match (parameter, default_parameters.get(i)) { + (&Ty::Unknown, _) | (_, None) => { + non_default_parameters.push(parameter.clone()) + } + (_, Some(default_parameter)) + if parameter != default_parameter => + { + non_default_parameters.push(parameter.clone()) + } + _ => (), + } + } + &non_default_parameters + } + } + } else { + self.parameters.0.as_ref() + }; + + f.write_joined(parameters_to_write, ", ")?; + write!(f, ">")?; + } + } + TypeCtor::AssociatedType(type_alias) => { + let trait_ = match type_alias.lookup(f.db).container { + AssocContainerId::TraitId(it) => it, + _ => panic!("not an associated type"), + }; + let trait_name = f.db.trait_data(trait_).name.clone(); + let name = f.db.type_alias_data(type_alias).name.clone(); + write!(f, "{}::{}", trait_name, name)?; + if self.parameters.len() > 0 { + write!(f, "<")?; + f.write_joined(&*self.parameters.0, ", ")?; + write!(f, ">")?; + } + } + TypeCtor::Closure { .. } => { + let sig = self.parameters[0] + .callable_sig(f.db) + .expect("first closure parameter should contain signature"); + let return_type_hint = sig.ret().display(f.db); + if sig.params().is_empty() { + write!(f, "|| -> {}", return_type_hint)?; + } else if f.omit_verbose_types() { + write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?; + } else { + write!(f, "|")?; + f.write_joined(sig.params(), ", ")?; + write!(f, "| -> {}", return_type_hint)?; + }; + } + } + Ok(()) + } +} + +impl HirDisplay for ProjectionTy { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + if f.should_truncate() { + return write!(f, "{}", TYPE_HINT_TRUNCATION); + } + + let trait_name = f.db.trait_data(self.trait_(f.db)).name.clone(); + write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?; + if self.parameters.len() > 1 { + write!(f, "<")?; + f.write_joined(&self.parameters[1..], ", ")?; + write!(f, ">")?; + } + write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?; + Ok(()) + } +} + +impl HirDisplay for Ty { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + if f.should_truncate() { + return write!(f, "{}", TYPE_HINT_TRUNCATION); + } + + match self { + Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, + Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, + Ty::Placeholder(id) => { + let generics = generics(f.db, id.parent); + let param_data = &generics.params.types[id.local_id]; + match param_data.provenance { + TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { + write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? + } + TypeParamProvenance::ArgumentImplTrait => { + write!(f, "impl ")?; + let bounds = f.db.generic_predicates_for_param(*id); + let substs = Substs::type_params_for_generics(&generics); + write_bounds_like_dyn_trait( + &bounds.iter().map(|b| b.clone().subst(&substs)).collect::>(), + f, + )?; + } + } + } + Ty::Bound(idx) => write!(f, "?{}", idx)?, + Ty::Dyn(predicates) | Ty::Opaque(predicates) => { + match self { + Ty::Dyn(_) => write!(f, "dyn ")?, + Ty::Opaque(_) => write!(f, "impl ")?, + _ => unreachable!(), + }; + write_bounds_like_dyn_trait(&predicates, f)?; + } + Ty::Unknown => write!(f, "{{unknown}}")?, + Ty::Infer(..) => write!(f, "_")?, + } + Ok(()) + } +} + +fn write_bounds_like_dyn_trait( + predicates: &[GenericPredicate], + f: &mut HirFormatter, +) -> fmt::Result { + // Note: This code is written to produce nice results (i.e. + // corresponding to surface Rust) for types that can occur in + // actual Rust. It will have weird results if the predicates + // aren't as expected (i.e. self types = $0, projection + // predicates for a certain trait come after the Implemented + // predicate for that trait). + let mut first = true; + let mut angle_open = false; + for p in predicates.iter() { + match p { + GenericPredicate::Implemented(trait_ref) => { + if angle_open { + write!(f, ">")?; + } + if !first { + write!(f, " + ")?; + } + // We assume that the self type is $0 (i.e. the + // existential) here, which is the only thing that's + // possible in actual Rust, and hence don't print it + write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?; + if trait_ref.substs.len() > 1 { + write!(f, "<")?; + f.write_joined(&trait_ref.substs[1..], ", ")?; + // there might be assoc type bindings, so we leave the angle brackets open + angle_open = true; + } + } + GenericPredicate::Projection(projection_pred) => { + // in types in actual Rust, these will always come + // after the corresponding Implemented predicate + if angle_open { + write!(f, ", ")?; + } else { + write!(f, "<")?; + angle_open = true; + } + let name = + f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone(); + write!(f, "{} = ", name)?; + projection_pred.ty.hir_fmt(f)?; + } + GenericPredicate::Error => { + if angle_open { + // impl Trait + write!(f, ", ")?; + } else if !first { + // impl Trait + {error} + write!(f, " + ")?; + } + p.hir_fmt(f)?; + } + } + first = false; + } + if angle_open { + write!(f, ">")?; + } + Ok(()) +} + +impl TraitRef { + fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> fmt::Result { + if f.should_truncate() { + return write!(f, "{}", TYPE_HINT_TRUNCATION); + } + + self.substs[0].hir_fmt(f)?; + if use_as { + write!(f, " as ")?; + } else { + write!(f, ": ")?; + } + write!(f, "{}", f.db.trait_data(self.trait_).name.clone())?; + if self.substs.len() > 1 { + write!(f, "<")?; + f.write_joined(&self.substs[1..], ", ")?; + write!(f, ">")?; + } + Ok(()) + } +} + +impl HirDisplay for TraitRef { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + self.hir_fmt_ext(f, false) + } +} + +impl HirDisplay for &GenericPredicate { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + HirDisplay::hir_fmt(*self, f) + } +} + +impl HirDisplay for GenericPredicate { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + if f.should_truncate() { + return write!(f, "{}", TYPE_HINT_TRUNCATION); + } + + match self { + GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, + GenericPredicate::Projection(projection_pred) => { + write!(f, "<")?; + projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; + write!( + f, + ">::{} = {}", + f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name, + projection_pred.ty.display(f.db) + )?; + } + GenericPredicate::Error => write!(f, "{{error}}")?, + } + Ok(()) + } +} + +impl HirDisplay for Obligation { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + match self { + Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), + Obligation::Projection(proj) => write!( + f, + "Normalize({} => {})", + proj.projection_ty.display(f.db), + proj.ty.display(f.db) + ), + } + } +} diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 69ad13952..571579cc4 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -41,13 +41,12 @@ mod marks; use std::ops::Deref; use std::sync::Arc; -use std::{fmt, iter, mem}; +use std::{iter, mem}; use hir_def::{ - expr::ExprId, generics::TypeParamProvenance, type_ref::Mutability, AdtId, AssocContainerId, - DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, + expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, + HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, }; -use hir_expand::name::Name; use ra_db::{impl_intern_key, salsa, CrateId}; use crate::{ @@ -55,7 +54,7 @@ use crate::{ primitive::{FloatTy, IntTy, Uncertain}, utils::{generics, make_mut_slice, Generics}, }; -use display::{HirDisplay, HirFormatter}; +use display::HirDisplay; pub use autoderef::autoderef; pub use infer::{do_infer_query, InferTy, InferenceResult}; @@ -836,369 +835,3 @@ impl TypeWalk for Ty { f(self, binders); } } - -const TYPE_HINT_TRUNCATION: &str = "…"; - -impl HirDisplay for &Ty { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - HirDisplay::hir_fmt(*self, f) - } -} - -impl HirDisplay for ApplicationTy { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - match self.ctor { - TypeCtor::Bool => write!(f, "bool")?, - TypeCtor::Char => write!(f, "char")?, - TypeCtor::Int(t) => write!(f, "{}", t)?, - TypeCtor::Float(t) => write!(f, "{}", t)?, - TypeCtor::Str => write!(f, "str")?, - TypeCtor::Slice => { - let t = self.parameters.as_single(); - write!(f, "[{}]", t.display(f.db))?; - } - TypeCtor::Array => { - let t = self.parameters.as_single(); - write!(f, "[{}; _]", t.display(f.db))?; - } - TypeCtor::RawPtr(m) => { - let t = self.parameters.as_single(); - write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?; - } - TypeCtor::Ref(m) => { - let t = self.parameters.as_single(); - let ty_display = if f.omit_verbose_types() { - t.display_truncated(f.db, f.max_size) - } else { - t.display(f.db) - }; - write!(f, "&{}{}", m.as_keyword_for_ref(), ty_display)?; - } - TypeCtor::Never => write!(f, "!")?, - TypeCtor::Tuple { .. } => { - let ts = &self.parameters; - if ts.len() == 1 { - write!(f, "({},)", ts[0].display(f.db))?; - } else { - write!(f, "(")?; - f.write_joined(&*ts.0, ", ")?; - write!(f, ")")?; - } - } - TypeCtor::FnPtr { .. } => { - let sig = FnSig::from_fn_ptr_substs(&self.parameters); - write!(f, "fn(")?; - f.write_joined(sig.params(), ", ")?; - write!(f, ") -> {}", sig.ret().display(f.db))?; - } - TypeCtor::FnDef(def) => { - let sig = f.db.callable_item_signature(def).subst(&self.parameters); - let name = match def { - CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(), - CallableDef::StructId(s) => f.db.struct_data(s).name.clone(), - CallableDef::EnumVariantId(e) => { - let enum_data = f.db.enum_data(e.parent); - enum_data.variants[e.local_id].name.clone() - } - }; - match def { - CallableDef::FunctionId(_) => write!(f, "fn {}", name)?, - CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { - write!(f, "{}", name)? - } - } - if self.parameters.len() > 0 { - let generics = generics(f.db, def.into()); - let (parent_params, self_param, type_params, _impl_trait_params) = - generics.provenance_split(); - let total_len = parent_params + self_param + type_params; - // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? - if total_len > 0 { - write!(f, "<")?; - f.write_joined(&self.parameters.0[..total_len], ", ")?; - write!(f, ">")?; - } - } - write!(f, "(")?; - f.write_joined(sig.params(), ", ")?; - write!(f, ") -> {}", sig.ret().display(f.db))?; - } - TypeCtor::Adt(def_id) => { - let name = match def_id { - AdtId::StructId(it) => f.db.struct_data(it).name.clone(), - AdtId::UnionId(it) => f.db.union_data(it).name.clone(), - AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), - }; - write!(f, "{}", name)?; - if self.parameters.len() > 0 { - write!(f, "<")?; - - let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); - let parameters_to_write = if f.omit_verbose_types() { - match self - .ctor - .as_generic_def() - .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) - .filter(|defaults| !defaults.is_empty()) - { - Option::None => self.parameters.0.as_ref(), - Option::Some(default_parameters) => { - for (i, parameter) in self.parameters.iter().enumerate() { - match (parameter, default_parameters.get(i)) { - (&Ty::Unknown, _) | (_, None) => { - non_default_parameters.push(parameter.clone()) - } - (_, Some(default_parameter)) - if parameter != default_parameter => - { - non_default_parameters.push(parameter.clone()) - } - _ => (), - } - } - &non_default_parameters - } - } - } else { - self.parameters.0.as_ref() - }; - - f.write_joined(parameters_to_write, ", ")?; - write!(f, ">")?; - } - } - TypeCtor::AssociatedType(type_alias) => { - let trait_ = match type_alias.lookup(f.db).container { - AssocContainerId::TraitId(it) => it, - _ => panic!("not an associated type"), - }; - let trait_name = f.db.trait_data(trait_).name.clone(); - let name = f.db.type_alias_data(type_alias).name.clone(); - write!(f, "{}::{}", trait_name, name)?; - if self.parameters.len() > 0 { - write!(f, "<")?; - f.write_joined(&*self.parameters.0, ", ")?; - write!(f, ">")?; - } - } - TypeCtor::Closure { .. } => { - let sig = self.parameters[0] - .callable_sig(f.db) - .expect("first closure parameter should contain signature"); - let return_type_hint = sig.ret().display(f.db); - if sig.params().is_empty() { - write!(f, "|| -> {}", return_type_hint)?; - } else if f.omit_verbose_types() { - write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?; - } else { - write!(f, "|")?; - f.write_joined(sig.params(), ", ")?; - write!(f, "| -> {}", return_type_hint)?; - }; - } - } - Ok(()) - } -} - -impl HirDisplay for ProjectionTy { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - let trait_name = f.db.trait_data(self.trait_(f.db)).name.clone(); - write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?; - if self.parameters.len() > 1 { - write!(f, "<")?; - f.write_joined(&self.parameters[1..], ", ")?; - write!(f, ">")?; - } - write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?; - Ok(()) - } -} - -impl HirDisplay for Ty { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - match self { - Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, - Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, - Ty::Placeholder(id) => { - let generics = generics(f.db, id.parent); - let param_data = &generics.params.types[id.local_id]; - match param_data.provenance { - TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { - write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? - } - TypeParamProvenance::ArgumentImplTrait => { - write!(f, "impl ")?; - let bounds = f.db.generic_predicates_for_param(*id); - let substs = Substs::type_params_for_generics(&generics); - write_bounds_like_dyn_trait( - &bounds.iter().map(|b| b.clone().subst(&substs)).collect::>(), - f, - )?; - } - } - } - Ty::Bound(idx) => write!(f, "?{}", idx)?, - Ty::Dyn(predicates) | Ty::Opaque(predicates) => { - match self { - Ty::Dyn(_) => write!(f, "dyn ")?, - Ty::Opaque(_) => write!(f, "impl ")?, - _ => unreachable!(), - }; - write_bounds_like_dyn_trait(&predicates, f)?; - } - Ty::Unknown => write!(f, "{{unknown}}")?, - Ty::Infer(..) => write!(f, "_")?, - } - Ok(()) - } -} - -fn write_bounds_like_dyn_trait( - predicates: &[GenericPredicate], - f: &mut HirFormatter, -) -> fmt::Result { - // Note: This code is written to produce nice results (i.e. - // corresponding to surface Rust) for types that can occur in - // actual Rust. It will have weird results if the predicates - // aren't as expected (i.e. self types = $0, projection - // predicates for a certain trait come after the Implemented - // predicate for that trait). - let mut first = true; - let mut angle_open = false; - for p in predicates.iter() { - match p { - GenericPredicate::Implemented(trait_ref) => { - if angle_open { - write!(f, ">")?; - } - if !first { - write!(f, " + ")?; - } - // We assume that the self type is $0 (i.e. the - // existential) here, which is the only thing that's - // possible in actual Rust, and hence don't print it - write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?; - if trait_ref.substs.len() > 1 { - write!(f, "<")?; - f.write_joined(&trait_ref.substs[1..], ", ")?; - // there might be assoc type bindings, so we leave the angle brackets open - angle_open = true; - } - } - GenericPredicate::Projection(projection_pred) => { - // in types in actual Rust, these will always come - // after the corresponding Implemented predicate - if angle_open { - write!(f, ", ")?; - } else { - write!(f, "<")?; - angle_open = true; - } - let name = - f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone(); - write!(f, "{} = ", name)?; - projection_pred.ty.hir_fmt(f)?; - } - GenericPredicate::Error => { - if angle_open { - // impl Trait - write!(f, ", ")?; - } else if !first { - // impl Trait + {error} - write!(f, " + ")?; - } - p.hir_fmt(f)?; - } - } - first = false; - } - if angle_open { - write!(f, ">")?; - } - Ok(()) -} - -impl TraitRef { - fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> fmt::Result { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - self.substs[0].hir_fmt(f)?; - if use_as { - write!(f, " as ")?; - } else { - write!(f, ": ")?; - } - write!(f, "{}", f.db.trait_data(self.trait_).name.clone())?; - if self.substs.len() > 1 { - write!(f, "<")?; - f.write_joined(&self.substs[1..], ", ")?; - write!(f, ">")?; - } - Ok(()) - } -} - -impl HirDisplay for TraitRef { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - self.hir_fmt_ext(f, false) - } -} - -impl HirDisplay for &GenericPredicate { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - HirDisplay::hir_fmt(*self, f) - } -} - -impl HirDisplay for GenericPredicate { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - match self { - GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, - GenericPredicate::Projection(projection_pred) => { - write!(f, "<")?; - projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; - write!( - f, - ">::{} = {}", - f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name, - projection_pred.ty.display(f.db) - )?; - } - GenericPredicate::Error => write!(f, "{{error}}")?, - } - Ok(()) - } -} - -impl HirDisplay for Obligation { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - match self { - Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), - Obligation::Projection(proj) => write!( - f, - "Normalize({} => {})", - proj.projection_ty.display(f.db), - proj.ty.display(f.db) - ), - } - } -} -- cgit v1.2.3 From 001dd6a2000ce4adada0ab6e4ed8fd67cb8eb569 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 14 Feb 2020 19:16:42 +0100 Subject: Make Self implement the trait inside trait default methods --- crates/ra_hir_ty/src/lower.rs | 32 +++++++++++++++++++++--- crates/ra_hir_ty/src/marks.rs | 1 + crates/ra_hir_ty/src/tests/traits.rs | 48 ++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index df24c16a3..6a2aded02 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -14,9 +14,9 @@ use hir_def::{ path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, - AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, - LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, - VariantId, + AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, + ImplId, LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, + UnionId, VariantId, }; use ra_arena::map::ArenaMap; use ra_db::CrateId; @@ -672,11 +672,35 @@ impl TraitEnvironment { pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc { let ctx = TyLoweringContext::new(db, &resolver) .with_type_param_mode(TypeParamLoweringMode::Placeholder); - let predicates = resolver + let mut predicates = resolver .where_predicates_in_scope() .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) .collect::>(); + if let Some(def) = resolver.generic_def() { + let container: Option = match def { + // FIXME: is there a function for this? + GenericDefId::FunctionId(f) => Some(f.lookup(db).container), + GenericDefId::AdtId(_) => None, + GenericDefId::TraitId(_) => None, + GenericDefId::TypeAliasId(t) => Some(t.lookup(db).container), + GenericDefId::ImplId(_) => None, + GenericDefId::EnumVariantId(_) => None, + GenericDefId::ConstId(c) => Some(c.lookup(db).container), + }; + if let Some(AssocContainerId::TraitId(trait_id)) = container { + // add `Self: Trait` to the environment in trait + // function default implementations (and hypothetical code + // inside consts or type aliases) + test_utils::tested_by!(trait_self_implements_self); + let substs = Substs::type_params(db, trait_id); + let trait_ref = TraitRef { trait_: trait_id, substs }; + let pred = GenericPredicate::Implemented(trait_ref); + + predicates.push(pred); + } + } + Arc::new(TraitEnvironment { predicates }) } } diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs index 0f754eb9c..ae47855e9 100644 --- a/crates/ra_hir_ty/src/marks.rs +++ b/crates/ra_hir_ty/src/marks.rs @@ -6,4 +6,5 @@ test_utils::marks!( type_var_resolves_to_int_var match_ergonomics_ref coerce_merge_fail_fallback + trait_self_implements_self ); diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 17611ddbf..aa2018944 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -299,6 +299,54 @@ fn test() { ); } +#[test] +fn trait_default_method_self_bound_implements_trait() { + test_utils::covers!(trait_self_implements_self); + assert_snapshot!( + infer(r#" +trait Trait { + fn foo(&self) -> i64; + fn bar(&self) -> { + let x = self.foo(); + } +} +"#), + @r###" + [27; 31) 'self': &Self + [53; 57) 'self': &Self + [62; 97) '{ ... }': () + [76; 77) 'x': i64 + [80; 84) 'self': &Self + [80; 90) 'self.foo()': i64 + "### + ); +} + +#[test] +fn trait_default_method_self_bound_implements_super_trait() { + test_utils::covers!(trait_self_implements_self); + assert_snapshot!( + infer(r#" +trait SuperTrait { + fn foo(&self) -> i64; +} +trait Trait: SuperTrait { + fn bar(&self) -> { + let x = self.foo(); + } +} +"#), + @r###" + [32; 36) 'self': &Self + [86; 90) 'self': &Self + [95; 130) '{ ... }': () + [109; 110) 'x': i64 + [113; 117) 'self': &Self + [113; 123) 'self.foo()': i64 + "### + ); +} + #[test] fn infer_project_associated_type() { // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234 -- cgit v1.2.3 From f47dc4de8d7aadea17dba023ece70e5b170274b1 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 14 Feb 2020 21:08:25 +0100 Subject: Check that impl self type matches up with expected self type in path mode Fixes #3144. --- crates/ra_hir_ty/src/marks.rs | 1 + crates/ra_hir_ty/src/method_resolution.rs | 9 +++++++ crates/ra_hir_ty/src/tests/method_resolution.rs | 32 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs index 0f754eb9c..4e0828425 100644 --- a/crates/ra_hir_ty/src/marks.rs +++ b/crates/ra_hir_ty/src/marks.rs @@ -4,6 +4,7 @@ test_utils::marks!( type_var_cycles_resolve_completely type_var_cycles_resolve_as_possible type_var_resolves_to_int_var + impl_self_type_match_without_receiver match_ergonomics_ref coerce_merge_fail_fallback ); diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 5283bff28..4f8c52433 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -425,6 +425,15 @@ fn iterate_inherent_methods( if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { continue; } + // we have to check whether the self type unifies with the type + // that the impl is for. If we have a receiver type, this + // already happens in `is_valid_candidate` above; if not, we + // check it here + if receiver_ty.is_none() && inherent_impl_substs(db, impl_block, self_ty).is_none() + { + test_utils::tested_by!(impl_self_type_match_without_receiver); + continue; + } if let Some(result) = callback(&self_ty.value, item) { return Some(result); } diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 1722563aa..1f767d324 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs @@ -963,6 +963,38 @@ fn test() { S2.into()<|>; } assert_eq!(t, "{unknown}"); } +#[test] +fn method_resolution_overloaded_method() { + test_utils::covers!(impl_self_type_match_without_receiver); + let t = type_at( + r#" +//- main.rs +struct Wrapper(T); +struct Foo(T); +struct Bar(T); + +impl Wrapper> { + pub fn new(foo_: T) -> Self { + Wrapper(Foo(foo_)) + } +} + +impl Wrapper> { + pub fn new(bar_: T) -> Self { + Wrapper(Bar(bar_)) + } +} + +fn main() { + let a = Wrapper::>::new(1.0); + let b = Wrapper::>::new(1.0); + (a, b)<|>; +} +"#, + ); + assert_eq!(t, "(Wrapper>, Wrapper>)") +} + #[test] fn method_resolution_encountering_fn_type() { type_at( -- cgit v1.2.3 From 3484d727c3b26e9596ec3bd671e2a76a87cdb5fd Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 15 Feb 2020 18:00:14 +0100 Subject: Extend analysis-stats a bit This adds some tools helpful when debugging nondeterminism in analysis-stats: - a `--randomize` option that analyses everything in random order - a `-vv` option that prints even more detail Also add a debug log if Chalk fuel is exhausted (which would be a source of nondeterminism, but didn't happen in my tests). I found one source of nondeterminism (rust-lang/chalk#331), but there are still other cases remaining. --- crates/ra_hir_ty/src/traits.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 88af61e87..ff8e75b48 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs @@ -60,6 +60,9 @@ impl TraitSolver { context.0.db.check_canceled(); let remaining = fuel.get(); fuel.set(remaining - 1); + if remaining == 0 { + log::debug!("fuel exhausted"); + } remaining > 0 }) } -- cgit v1.2.3 From e14e7ffa34bf9a458681fe7490ac2d51b02ff908 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 16 Feb 2020 12:57:19 +0100 Subject: Fix coercion of &T to itself The autoderef coercion logic did not handle matching placeholders. This led to some type mismatches. --- crates/ra_hir_ty/src/infer/unify.rs | 2 ++ crates/ra_hir_ty/src/tests/coercion.rs | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index fe05642ae..1dc842f40 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs @@ -249,6 +249,8 @@ impl InferenceTable { match (ty1, ty2) { (Ty::Unknown, _) | (_, Ty::Unknown) => true, + (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true, + (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index fc5ef36a5..42330b269 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -526,3 +526,25 @@ fn test() { "### ); } + +#[test] +fn coerce_placeholder_ref() { + // placeholders should unify, even behind references + assert_snapshot!( + infer_with_mismatches(r#" +struct S { t: T } +impl S { + fn get(&self) -> &TT { + &self.t + } +} +"#, true), + @r###" + [51; 55) 'self': &S + [64; 87) '{ ... }': &TT + [74; 81) '&self.t': &TT + [75; 79) 'self': &S + [75; 81) 'self.t': TT + "### + ); +} -- cgit v1.2.3