From a1e0442623e2393d034e994d2d33f930e0573ee2 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 28 Nov 2023 03:11:01 +0100 Subject: [PATCH] WIP: add support for the `move` type modifier --- ast/src/nodes.rs | 2 + ast/src/parser.rs | 25 +++++++ compiler/src/hir.rs | 25 +++++++ compiler/src/type_check/expressions.rs | 18 ++--- compiler/src/type_check/methods.rs | 2 +- compiler/src/type_check/mod.rs | 56 ++++++++------- types/src/check.rs | 80 ++++++++++++++-------- types/src/format.rs | 22 +++++- types/src/lib.rs | 95 +++++++++++++++++++------- types/src/resolve.rs | 23 ++++--- types/src/specialize.rs | 4 +- types/src/test.rs | 2 +- 12 files changed, 243 insertions(+), 111 deletions(-) diff --git a/ast/src/nodes.rs b/ast/src/nodes.rs index 7d76f44fe..2bb67e120 100644 --- a/ast/src/nodes.rs +++ b/ast/src/nodes.rs @@ -972,6 +972,7 @@ pub enum Type { Ref(Box), Mut(Box), Uni(Box), + Owned(Box), Closure(Box), Tuple(Box), } @@ -983,6 +984,7 @@ impl Node for Type { Type::Ref(ref typ) => typ.location(), Type::Mut(ref typ) => typ.location(), Type::Uni(ref typ) => typ.location(), + Type::Owned(ref typ) => typ.location(), Type::Closure(ref typ) => typ.location(), Type::Tuple(ref typ) => typ.location(), } diff --git a/ast/src/parser.rs b/ast/src/parser.rs index 864b64fd3..c9a2ff16a 100644 --- a/ast/src/parser.rs +++ b/ast/src/parser.rs @@ -466,6 +466,9 @@ impl Parser { TokenKind::Fn => Type::Closure(Box::new(self.closure_type(start)?)), TokenKind::Ref => Type::Ref(Box::new(self.reference_type(start)?)), TokenKind::Mut => Type::Mut(Box::new(self.reference_type(start)?)), + TokenKind::Move => { + Type::Owned(Box::new(self.reference_type(start)?)) + } TokenKind::Uni => Type::Uni(Box::new(self.reference_type(start)?)), TokenKind::ParenOpen => { Type::Tuple(Box::new(self.tuple_type(start)?)) @@ -3879,6 +3882,28 @@ mod tests { ); } + #[test] + fn test_type_reference_with_owned_reference_type() { + let mut parser = parser("move A"); + let start = parser.require().unwrap(); + + assert_eq!( + parser.type_reference(start).unwrap(), + Type::Owned(Box::new(ReferenceType { + type_reference: ReferrableType::Named(Box::new(TypeName { + name: Constant { + source: None, + name: "A".to_string(), + location: cols(6, 6), + }, + arguments: None, + location: cols(6, 6) + })), + location: cols(1, 6) + })) + ); + } + #[test] fn test_type_reference_with_double_reference() { let mut parser = parser("ref ref A"); diff --git a/compiler/src/hir.rs b/compiler/src/hir.rs index ec28ad7d2..4daad6064 100644 --- a/compiler/src/hir.rs +++ b/compiler/src/hir.rs @@ -658,6 +658,7 @@ pub(crate) enum Type { Ref(Box), Mut(Box), Uni(Box), + Owned(Box), Closure(Box), Tuple(Box), } @@ -669,6 +670,7 @@ impl Type { Type::Ref(ref node) => &node.location, Type::Mut(ref node) => &node.location, Type::Uni(ref node) => &node.location, + Type::Owned(ref node) => &node.location, Type::Closure(ref node) => &node.location, Type::Tuple(ref node) => &node.location, } @@ -1542,6 +1544,7 @@ impl<'a> LowerToHir<'a> { } ast::Type::Ref(node) => Type::Ref(self.reference_type(*node)), ast::Type::Mut(node) => Type::Mut(self.reference_type(*node)), + ast::Type::Owned(node) => Type::Owned(self.reference_type(*node)), ast::Type::Uni(node) => Type::Uni(self.reference_type(*node)), ast::Type::Closure(node) => Type::Closure(self.closure_type(*node)), ast::Type::Tuple(node) => Type::Tuple(self.tuple_type(*node)), @@ -3330,6 +3333,28 @@ mod tests { ); } + #[test] + fn test_lower_owned_reference_type() { + let hir = lower_type("move B"); + + assert_eq!( + hir, + Type::Owned(Box::new(ReferenceType { + type_reference: ReferrableType::Named(Box::new(TypeName { + source: None, + resolved_type: types::TypeRef::Unknown, + name: Constant { + name: "B".to_string(), + location: cols(14, 14) + }, + arguments: Vec::new(), + location: cols(14, 14) + })), + location: cols(9, 14) + })) + ); + } + #[test] fn test_lower_closure_type() { let hir = lower_type("fn (A) -> C"); diff --git a/compiler/src/type_check/expressions.rs b/compiler/src/type_check/expressions.rs index 0a33a82ce..217828e9a 100644 --- a/compiler/src/type_check/expressions.rs +++ b/compiler/src/type_check/expressions.rs @@ -353,7 +353,7 @@ impl MethodCall { }; // If the receiver is rigid, it may introduce additional type arguments - // through its type parameter requirements. These are typed as Infer(), + // through its type parameter requirements. These are typed as Any(), // but we want them as rigid types. In addition, we need to take care or // remapping any bound parameters. // @@ -363,7 +363,7 @@ impl MethodCall { // handle it here when/if necessary. if receiver.is_rigid_type_parameter(&state.db) { for val in type_arguments.values_mut() { - if let TypeRef::Infer(TypeId::TypeParameter(id)) = val { + if let TypeRef::Any(TypeId::TypeParameter(id)) = val { *val = TypeRef::Owned(TypeId::RigidTypeParameter( bounds.get(*id).unwrap_or(*id), )); @@ -3935,11 +3935,8 @@ impl<'a> CheckMethodBody<'a> { scope: &mut LexicalScope, ) -> TypeRef { let expr_type = self.expression(&mut node.value, scope); - let rules = Rules { - type_parameters_as_rigid: true, - type_parameters_as_owned: true, - ..Default::default() - }; + let rules = + Rules { type_parameters_as_rigid: true, ..Default::default() }; let type_scope = TypeScope::with_bounds( self.module, @@ -4272,11 +4269,8 @@ impl<'a> CheckMethodBody<'a> { node: &mut hir::Type, self_type: TypeId, ) -> TypeRef { - let rules = Rules { - type_parameters_as_rigid: true, - type_parameters_as_owned: true, - ..Default::default() - }; + let rules = + Rules { type_parameters_as_rigid: true, ..Default::default() }; let type_scope = TypeScope::with_bounds( self.module, self_type, diff --git a/compiler/src/type_check/methods.rs b/compiler/src/type_check/methods.rs index b38626091..ca8a208da 100644 --- a/compiler/src/type_check/methods.rs +++ b/compiler/src/type_check/methods.rs @@ -1007,7 +1007,7 @@ impl<'a> DefineMethods<'a> { let args = class_id .type_parameters(self.db()) .into_iter() - .map(|param| TypeRef::Infer(TypeId::TypeParameter(param))) + .map(|param| TypeRef::Any(TypeId::TypeParameter(param))) .collect(); ClassInstance::with_types(self.db_mut(), class_id, args) diff --git a/compiler/src/type_check/mod.rs b/compiler/src/type_check/mod.rs index 7a0d3988f..8803b9733 100644 --- a/compiler/src/type_check/mod.rs +++ b/compiler/src/type_check/mod.rs @@ -19,6 +19,7 @@ pub(crate) mod methods; #[derive(Eq, PartialEq)] enum RefKind { + Default, Owned, Ref, Mut, @@ -28,6 +29,12 @@ enum RefKind { impl RefKind { fn into_type_ref(self, id: TypeId) -> TypeRef { match self { + Self::Default => match id { + TypeId::TypeParameter(_) | TypeId::RigidTypeParameter(_) => { + TypeRef::Any(id) + } + _ => TypeRef::Owned(id), + }, Self::Owned => TypeRef::Owned(id), Self::Ref => TypeRef::Ref(id), Self::Mut => TypeRef::Mut(id), @@ -97,10 +104,6 @@ impl<'a> TypeScope<'a> { /// Rules to apply when defining and checking the types of type signatures. #[derive(Copy, Clone)] pub(crate) struct Rules { - /// When set to `true`, type parameters are defined as owned values; rather - /// than allowing both owned values and references. - pub(crate) type_parameters_as_owned: bool, - /// When set to `true`, type parameters are defined as rigid parameters. pub(crate) type_parameters_as_rigid: bool, @@ -114,7 +117,6 @@ pub(crate) struct Rules { impl Default for Rules { fn default() -> Self { Self { - type_parameters_as_owned: false, type_parameters_as_rigid: false, allow_private_types: true, allow_refs: true, @@ -169,7 +171,7 @@ impl<'a> DefineTypeSignature<'a> { fn define_type(&mut self, node: &mut hir::Type) -> TypeRef { match node { hir::Type::Named(ref mut n) => { - self.define_type_name(n, RefKind::Owned) + self.define_type_name(n, RefKind::Default) } hir::Type::Ref(_) | hir::Type::Mut(_) if !self.rules.allow_refs => { self.state.diagnostics.error( @@ -189,6 +191,9 @@ impl<'a> DefineTypeSignature<'a> { hir::Type::Uni(ref mut n) => { self.define_reference_type(n, RefKind::Uni) } + hir::Type::Owned(ref mut n) => { + self.define_reference_type(n, RefKind::Owned) + } hir::Type::Closure(ref mut n) => { self.define_closure_type(n, RefKind::Owned) } @@ -288,7 +293,7 @@ impl<'a> DefineTypeSignature<'a> { // handling them first. match name.as_str() { "Never" => { - if kind == RefKind::Owned { + if kind == RefKind::Default { TypeRef::Never } else { self.state.diagnostics.error( @@ -403,30 +408,22 @@ impl<'a> DefineTypeSignature<'a> { TypeId::TypeParameter(param_id) }; - match kind { - RefKind::Owned if self.rules.type_parameters_as_owned => { - TypeRef::Owned(type_id) - } - RefKind::Owned => TypeRef::Infer(type_id), - RefKind::Uni => TypeRef::Uni(type_id), - RefKind::Ref => TypeRef::Ref(type_id), - RefKind::Mut => { - if !param_id.is_mutable(self.db()) { - self.state.diagnostics.error( - DiagnosticId::InvalidType, - format!( - "the type 'mut {name}' is invalid, as '{name}' \ + if let RefKind::Mut = kind { + if !param_id.is_mutable(self.db()) { + self.state.diagnostics.error( + DiagnosticId::InvalidType, + format!( + "the type 'mut {name}' is invalid, as '{name}' \ might be immutable at runtime", - name = id.name(self.db()), - ), - self.file(), - node.location.clone(), - ); - } - - TypeRef::Mut(type_id) + name = id.name(self.db()), + ), + self.file(), + node.location.clone(), + ); } } + + kind.into_type_ref(type_id) } fn define_closure_type( @@ -623,6 +620,7 @@ impl<'a> CheckTypeSignature<'a> { hir::Type::Ref(ref n) => self.check_reference_type(n), hir::Type::Uni(ref n) => self.check_reference_type(n), hir::Type::Mut(ref n) => self.check_reference_type(n), + hir::Type::Owned(ref n) => self.check_reference_type(n), hir::Type::Closure(ref n) => self.check_closure_type(n), hir::Type::Tuple(ref n) => self.check_tuple_type(n), } @@ -736,7 +734,7 @@ impl<'a> CheckTypeSignature<'a> { for (param, node) in parameters.into_iter().zip(node.arguments.iter()) { let arg = arguments.get(param).unwrap(); - let exp = TypeRef::Infer(TypeId::TypeParameter(param)); + let exp = TypeRef::Any(TypeId::TypeParameter(param)); let mut env = Environment::new( arg.type_arguments(self.db()), exp_args.clone(), diff --git a/types/src/check.rs b/types/src/check.rs index 4c9477775..507a90ec5 100644 --- a/types/src/check.rs +++ b/types/src/check.rs @@ -22,8 +22,8 @@ struct Rules { /// types. relaxed_ownership: bool, - /// When encountering an Infer() type, turn it into a rigid type. - infer_as_rigid: bool, + /// When encountering an Any() type, turn it into a rigid type. + any_as_rigid: bool, /// If we're performing a type-check as part of a type cast. /// @@ -36,7 +36,7 @@ impl Rules { Rules { class_subtyping: Subtyping::No, relaxed_ownership: false, - infer_as_rigid: false, + any_as_rigid: false, type_cast: false, } } @@ -50,12 +50,12 @@ impl Rules { } fn infer_as_rigid(mut self) -> Rules { - self.infer_as_rigid = true; + self.any_as_rigid = true; self } fn dont_infer_as_rigid(mut self) -> Rules { - self.infer_as_rigid = false; + self.any_as_rigid = false; self } @@ -281,7 +281,7 @@ impl<'a> TypeChecker<'a> { // otherwise we may end up comparing e.g. a class instance to the rigid // type parameter on the right, which would always fail. // - // This is OK because in practise, Infer() only shows up on the left in + // This is OK because in practise, Any() only shows up on the left in // a select few cases. let rules = rules.dont_infer_as_rigid(); let original_right = right; @@ -317,7 +317,7 @@ impl<'a> TypeChecker<'a> { TypeRef::Owned(TypeId::RigidTypeParameter(rhs)) => { lhs == rhs } - TypeRef::Infer(right_id) => { + TypeRef::Any(right_id) => { self.check_rigid_with_type_id(lhs, right_id, env, rules) } TypeRef::Placeholder(id) => self @@ -335,7 +335,7 @@ impl<'a> TypeChecker<'a> { } } TypeRef::Owned(left_id) => match right { - TypeRef::Owned(right_id) | TypeRef::Infer(right_id) => { + TypeRef::Owned(right_id) | TypeRef::Any(right_id) => { self.check_type_id(left_id, right_id, env, rules) } TypeRef::Ref(right_id) @@ -364,7 +364,7 @@ impl<'a> TypeChecker<'a> { }, TypeRef::Uni(left_id) => match right { TypeRef::Owned(right_id) - | TypeRef::Infer(right_id) + | TypeRef::Any(right_id) | TypeRef::Uni(right_id) => { self.check_type_id(left_id, right_id, env, rules) } @@ -385,33 +385,38 @@ impl<'a> TypeChecker<'a> { TypeRef::Error => true, _ => false, }, - TypeRef::Infer(left_id) => match right { + TypeRef::Any(left_id) => match right { // Mut and Owned are not allowed because we don't know the // runtime ownership of our value. Ref is fine, because we can // always turn an Owned/Ref/Mut/etc into a Ref. - TypeRef::Infer(right_id) | TypeRef::Ref(right_id) => { + TypeRef::Any(right_id) | TypeRef::Ref(right_id) => { self.check_type_id(left_id, right_id, env, rules) } - TypeRef::Placeholder(id) => self - .check_type_id_with_placeholder( + TypeRef::Placeholder(id) => { + if id.owned { + return false; + } + + self.check_type_id_with_placeholder( left, left_id, original_right, id, env, rules, - ), + ) + } TypeRef::Error => true, _ => false, }, TypeRef::Ref(left_id) => match right { - TypeRef::Infer(TypeId::TypeParameter(pid)) + TypeRef::Any(TypeId::TypeParameter(pid)) if pid.is_mutable(self.db) && !left.is_value_type(self.db) => { false } - TypeRef::Ref(right_id) | TypeRef::Infer(right_id) => { + TypeRef::Ref(right_id) | TypeRef::Any(right_id) => { self.check_type_id(left_id, right_id, env, rules) } TypeRef::Owned(right_id) @@ -422,6 +427,10 @@ impl<'a> TypeChecker<'a> { self.check_type_id(left_id, right_id, env, rules) } TypeRef::Placeholder(id) => { + if id.owned && !left.is_value_type(self.db) { + return false; + } + if let Some(req) = id.required(self.db) { if req.is_mutable(self.db) && !left.is_value_type(self.db) @@ -443,7 +452,7 @@ impl<'a> TypeChecker<'a> { _ => false, }, TypeRef::Mut(left_id) => match right { - TypeRef::Ref(right_id) | TypeRef::Infer(right_id) => { + TypeRef::Ref(right_id) | TypeRef::Any(right_id) => { self.check_type_id(left_id, right_id, env, rules) } TypeRef::Mut(right_id) => self.check_type_id( @@ -457,15 +466,20 @@ impl<'a> TypeChecker<'a> { { self.check_type_id(left_id, right_id, env, rules) } - TypeRef::Placeholder(id) => self - .check_type_id_with_placeholder( + TypeRef::Placeholder(id) => { + if id.owned && !left.is_value_type(self.db) { + return false; + } + + self.check_type_id_with_placeholder( left, left_id, original_right, id, env, rules, - ), + ) + } TypeRef::Error => true, _ => false, }, @@ -500,15 +514,20 @@ impl<'a> TypeChecker<'a> { TypeRef::Owned(TypeId::ClassInstance(ins)) => { rules.type_cast && ins.instance_of().0 == INT_ID } - TypeRef::Placeholder(right_id) => self - .check_type_id_with_placeholder( + TypeRef::Placeholder(right_id) => { + if right_id.owned { + return false; + } + + self.check_type_id_with_placeholder( left, left_id, original_right, right_id, env, rules, - ), + ) + } _ => false, }, _ => false, @@ -862,7 +881,7 @@ impl<'a> TypeChecker<'a> { | TypeRef::Mut(id) | TypeRef::UniRef(id) | TypeRef::UniMut(id) - | TypeRef::Infer(id) => match id { + | TypeRef::Any(id) => match id { TypeId::ClassInstance(lhs) => { self.check_class_with_trait(lhs, right, env, rules) } @@ -992,9 +1011,11 @@ impl<'a> TypeChecker<'a> { rules: Rules, ) -> TypeRef { let result = match typ { - TypeRef::Owned(TypeId::TypeParameter(id)) - | TypeRef::Uni(TypeId::TypeParameter(id)) - | TypeRef::Infer(TypeId::TypeParameter(id)) + TypeRef::Owned(TypeId::TypeParameter(id)) => self + .resolve_type_parameter(typ, id, arguments, rules) + .as_owned(self.db), + TypeRef::Uni(TypeId::TypeParameter(id)) + | TypeRef::Any(TypeId::TypeParameter(id)) | TypeRef::Pointer(TypeId::TypeParameter(id)) => { self.resolve_type_parameter(typ, id, arguments, rules) } @@ -1011,9 +1032,7 @@ impl<'a> TypeChecker<'a> { }; match result { - TypeRef::Infer(TypeId::TypeParameter(id)) - if rules.infer_as_rigid => - { + TypeRef::Any(TypeId::TypeParameter(id)) if rules.any_as_rigid => { TypeRef::Owned(TypeId::RigidTypeParameter(id)) } _ => result, @@ -1103,6 +1122,7 @@ mod tests { let param = new_parameter(&mut db, "T"); let to_string = new_trait(&mut db, "ToString"); let var1 = TypePlaceholder::alloc(&mut db, None); + let var2 = TypePlaceholder::alloc(&mut db, Some(param)); param.add_requirements(&mut db, vec![trait_instance(to_string)]); diff --git a/types/src/format.rs b/types/src/format.rs index 2e39d851f..d84d1c8b1 100644 --- a/types/src/format.rs +++ b/types/src/format.rs @@ -91,6 +91,10 @@ impl<'a> TypeFormatter<'a> { Some(TypeRef::Placeholder(id)) if id.value(self.db).is_none() => { + if id.owned { + self.write_ownership("move "); + } + // Placeholders without values aren't useful to show to the // developer, so we show the type parameter instead. // @@ -154,8 +158,14 @@ pub trait FormatType { impl FormatType for TypePlaceholderId { fn format_type(&self, buffer: &mut TypeFormatter) { + if self.owned { + buffer.write_ownership("move "); + } + if let Some(value) = self.value(buffer.db) { value.format_type(buffer); + } else if let Some(req) = self.required(buffer.db) { + req.format_type(buffer); } else { buffer.write("?"); } @@ -184,6 +194,10 @@ impl FormatType for TypeParameterId { if let Some(arg) = buffer.type_arguments.and_then(|a| a.get(*self)) { if let TypeRef::Placeholder(p) = arg { + if p.owned { + buffer.write_ownership("move "); + } + match p.value(buffer.db) { Some(t) if t.as_type_parameter(buffer.db) == Some(*self) => @@ -338,8 +352,12 @@ impl FormatType for ClosureId { impl FormatType for TypeRef { fn format_type(&self, buffer: &mut TypeFormatter) { match self { + TypeRef::Owned(id @ TypeId::TypeParameter(_)) => { + buffer.write_ownership("move "); + id.format_type(buffer); + } TypeRef::Owned(id) => id.format_type(buffer), - TypeRef::Infer(id) => id.format_type(buffer), + TypeRef::Any(id) => id.format_type(buffer), TypeRef::Uni(id) => { buffer.write_ownership("uni "); id.format_type(buffer); @@ -831,7 +849,7 @@ mod tests { format_type(&db, TypeRef::UniRef(string_ins)), "uni ref String".to_string() ); - assert_eq!(format_type(&db, TypeRef::Infer(param)), "T".to_string()); + assert_eq!(format_type(&db, TypeRef::Any(param)), "T".to_string()); assert_eq!( format_type(&db, TypeRef::Ref(string_ins)), "ref String".to_string() diff --git a/types/src/lib.rs b/types/src/lib.rs index 01befa91a..692c71b65 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -105,6 +105,14 @@ pub const FIELDS_LIMIT: usize = u8::MAX as usize; /// The maximum number of values that can be stored in an array literal. pub const ARRAY_LIMIT: usize = u16::MAX as usize; +/// The requirement of a type inference placeholder. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum PlaceholderRequirement { + None, + Owned(TypeParameterId), + Any(TypeParameterId), +} + /// A type inference placeholder. /// /// A type placeholder reprents a value of which the exact type isn't @@ -136,8 +144,8 @@ pub struct TypePlaceholder { /// fields). value: Cell, - /// The type parameter a type must be compatible with before it can be - /// assigned to this type variable. + /// The type parameter requirement that must be met before a type is + /// compatible with this placeholder. required: Option, } @@ -146,19 +154,36 @@ impl TypePlaceholder { db: &mut Database, required: Option, ) -> TypePlaceholderId { - let id = db.type_placeholders.len(); + assert!(db.type_placeholders.len() <= u32::MAX as usize); + + let id = db.type_placeholders.len() as u32; let typ = TypePlaceholder { value: Cell::new(TypeRef::Unknown), required }; db.type_placeholders.push(typ); - TypePlaceholderId(id) + TypePlaceholderId { id, owned: false } } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct TypePlaceholderId(pub(crate) usize); +pub struct TypePlaceholderId { + id: u32, + + /// A flag that indicates a value must be owned for it to be compatible with + /// this placeholder. + /// + /// This is stored in the ID/reference as in various instances type + /// placeholders are created ahead of time, at which point we do not yet + /// know if a value must be owned or not. By storing this in the ID we can + /// adjust it accordingly where necessary. + owned: bool, +} impl TypePlaceholderId { + pub fn as_owned(self) -> TypePlaceholderId { + TypePlaceholderId { id: self.id, owned: true } + } + pub fn value(self, db: &Database) -> Option { // Chains of type variables are very rare in practise, but they _can_ // occur and thus must be handled. Because they are so rare and unlikely @@ -181,7 +206,7 @@ impl TypePlaceholderId { // Assigning placeholders to themselves isn't useful and results in // resolve() getting stuck. if let TypeRef::Placeholder(id) = value { - if id.0 == self.0 { + if id.id == self.id { return; } } @@ -190,7 +215,7 @@ impl TypePlaceholderId { } fn get(self, db: &Database) -> &TypePlaceholder { - &db.type_placeholders[self.0] + &db.type_placeholders[self.id as usize] } } @@ -3065,12 +3090,12 @@ pub enum TypeRef { /// A mutable, temporary and unique reference. UniMut(TypeId), - /// A type of which the ownership should be inferred. + /// A type of which the ownership can be anything. /// /// This variant is only used with type parameters. We wrap a TypeId here so /// we can reuse various functions more easily, such as those used for /// type-checking; instead of having to special-case this variant. - Infer(TypeId), + Any(TypeId), /// A type that signals something never happens. /// @@ -3168,7 +3193,7 @@ impl TypeRef { | TypeRef::Mut(id) | TypeRef::UniRef(id) | TypeRef::UniMut(id) - | TypeRef::Infer(id) => Ok(id), + | TypeRef::Any(id) => Ok(id), TypeRef::Placeholder(id) => { id.value(db).ok_or(self).and_then(|t| t.type_id(db)) } @@ -3258,7 +3283,7 @@ impl TypeRef { pub fn is_owned_or_uni(self, db: &Database) -> bool { match self { - TypeRef::Owned(_) | TypeRef::Uni(_) | TypeRef::Infer(_) => true, + TypeRef::Owned(_) | TypeRef::Uni(_) | TypeRef::Any(_) => true, TypeRef::Placeholder(id) => { id.value(db).map_or(false, |v| v.is_owned_or_uni(db)) } @@ -3268,7 +3293,7 @@ impl TypeRef { pub fn is_owned(self, db: &Database) -> bool { match self { - TypeRef::Owned(_) | TypeRef::Infer(_) => true, + TypeRef::Owned(_) | TypeRef::Any(_) => true, TypeRef::Placeholder(id) => { id.value(db).map_or(false, |v| v.is_owned(db)) } @@ -3298,7 +3323,7 @@ impl TypeRef { | TypeId::RigidTypeParameter(_) | TypeId::AtomicTypeParameter(_), ) - | TypeRef::Infer( + | TypeRef::Any( TypeId::TypeParameter(_) | TypeId::RigidTypeParameter(_) | TypeId::AtomicTypeParameter(_), @@ -3434,7 +3459,7 @@ impl TypeRef { TypeRef::Owned(_) | TypeRef::Uni(_) | TypeRef::Mut(_) - | TypeRef::Infer(_) + | TypeRef::Any(_) | TypeRef::Pointer(_) | TypeRef::Error | TypeRef::Unknown @@ -3591,7 +3616,7 @@ impl TypeRef { pub fn as_ref(self, db: &Database) -> Self { match self { - TypeRef::Owned(id) | TypeRef::Infer(id) | TypeRef::Mut(id) => { + TypeRef::Owned(id) | TypeRef::Any(id) | TypeRef::Mut(id) => { TypeRef::Ref(id) } TypeRef::Uni(id) | TypeRef::UniMut(id) => TypeRef::UniRef(id), @@ -3635,7 +3660,7 @@ impl TypeRef { id @ TypeId::RigidTypeParameter(pid) | id @ TypeId::TypeParameter(pid), ) - | TypeRef::Infer( + | TypeRef::Any( id @ TypeId::RigidTypeParameter(pid) | id @ TypeId::TypeParameter(pid), ) => { @@ -3656,7 +3681,7 @@ impl TypeRef { pub fn force_as_mut(self, db: &Database) -> Self { match self { - TypeRef::Owned(id) | TypeRef::Infer(id) => TypeRef::Mut(id), + TypeRef::Owned(id) | TypeRef::Any(id) => TypeRef::Mut(id), TypeRef::Uni(id) => TypeRef::UniMut(id), TypeRef::Placeholder(id) => { id.value(db).map_or(self, |v| v.as_mut(db)) @@ -3689,7 +3714,7 @@ impl TypeRef { pub fn as_uni(self, db: &Database) -> Self { match self { TypeRef::Owned(id) - | TypeRef::Infer(id) + | TypeRef::Any(id) | TypeRef::Uni(id) | TypeRef::Mut(id) | TypeRef::Ref(id) => TypeRef::Uni(id), @@ -3707,9 +3732,10 @@ impl TypeRef { | TypeRef::Mut(id) | TypeRef::UniRef(id) | TypeRef::UniMut(id) => TypeRef::Owned(id), - TypeRef::Placeholder(id) => { - id.value(db).map_or(self, |v| v.as_owned(db)) - } + TypeRef::Placeholder(id) => match id.value(db) { + Some(v) => v.as_owned(db), + _ => TypeRef::Placeholder(id.as_owned()), + }, _ => self, } } @@ -3758,14 +3784,14 @@ impl TypeRef { | TypeRef::Uni(TypeId::TypeParameter(id)) | TypeRef::Ref(TypeId::TypeParameter(id)) | TypeRef::Mut(TypeId::TypeParameter(id)) - | TypeRef::Infer(TypeId::TypeParameter(id)) + | TypeRef::Any(TypeId::TypeParameter(id)) | TypeRef::Owned(TypeId::RigidTypeParameter(id)) | TypeRef::Uni(TypeId::RigidTypeParameter(id)) | TypeRef::Ref(TypeId::RigidTypeParameter(id)) | TypeRef::Mut(TypeId::RigidTypeParameter(id)) | TypeRef::UniRef(TypeId::RigidTypeParameter(id)) | TypeRef::UniMut(TypeId::RigidTypeParameter(id)) - | TypeRef::Infer(TypeId::RigidTypeParameter(id)) => Some(id), + | TypeRef::Any(TypeId::RigidTypeParameter(id)) => Some(id), TypeRef::Placeholder(id) => { id.value(db).and_then(|v| v.as_type_parameter(db)) } @@ -3843,7 +3869,7 @@ impl TypeRef { | TypeRef::Mut(id) | TypeRef::UniRef(id) | TypeRef::UniMut(id) - | TypeRef::Infer(id) => match id { + | TypeRef::Any(id) => match id { TypeId::ClassInstance(ins) if ins.instance_of.is_generic(db) => { @@ -3974,7 +4000,7 @@ impl TypeRef { | TypeRef::UniRef(TypeId::ClassInstance(ins)) => { ins.instance_of.shape(db, Shape::Ref) } - TypeRef::Infer( + TypeRef::Any( TypeId::TypeParameter(id) | TypeId::RigidTypeParameter(id), ) | TypeRef::Owned( @@ -5294,4 +5320,23 @@ mod tests { assert_eq!(rec, mutable(instance(proc))); } + + #[test] + fn test_type_placeholder_id_as_owned() { + let id = TypePlaceholderId { id: 1, owned: false }; + + assert_eq!(id.as_owned(), TypePlaceholderId { id: 1, owned: true }); + } + + #[test] + fn test_type_ref_as_owned() { + let mut db = Database::new(); + let id = TypePlaceholder::alloc(&mut db, None); + let typ = TypeRef::Placeholder(id); + + assert_eq!( + typ.as_owned(&db), + TypeRef::Placeholder(TypePlaceholderId { id: id.id, owned: true }) + ); + } } diff --git a/types/src/resolve.rs b/types/src/resolve.rs index 77fe39eea..7a46ca37d 100644 --- a/types/src/resolve.rs +++ b/types/src/resolve.rs @@ -94,17 +94,19 @@ impl<'a> TypeResolver<'a> { self.cached.insert(value, value); let resolved = match value { - TypeRef::Owned(id) | TypeRef::Infer(id) => { - match self.resolve_type_id(id) { - Either::Left(res) => TypeRef::Owned(res), - Either::Right(typ) => typ, - } - } + TypeRef::Owned(id) => match self.resolve_type_id(id) { + Either::Left(res) => TypeRef::Owned(res), + Either::Right(typ) => typ.as_owned(self.db), + }, + TypeRef::Any(id) => match self.resolve_type_id(id) { + Either::Left(res) => TypeRef::Owned(res), + Either::Right(typ) => typ, + }, TypeRef::Pointer(id) => match self.resolve_type_id(id) { Either::Left(res) => TypeRef::Pointer(res), Either::Right( TypeRef::Owned(id) - | TypeRef::Infer(id) + | TypeRef::Any(id) | TypeRef::Pointer(id) | TypeRef::Uni(id), ) => TypeRef::Pointer(id), @@ -829,9 +831,12 @@ mod tests { assert_eq!( resolve(&mut db, &args, &bounds, owned(parameter(param))), - placeholder(TypePlaceholderId(0)) + placeholder(TypePlaceholderId { id: 0, owned: true }) ); - assert_eq!(TypePlaceholderId(0).required(&db), Some(bound)); + assert_eq!( + TypePlaceholderId { id: 0, owned: false }.required(&db), + Some(bound) + ); } } diff --git a/types/src/specialize.rs b/types/src/specialize.rs index b4d474d58..dc02e8343 100644 --- a/types/src/specialize.rs +++ b/types/src/specialize.rs @@ -57,7 +57,7 @@ impl<'a, 'b, 'c> TypeSpecializer<'a, 'b, 'c> { TypeRef::Owned( TypeId::TypeParameter(pid) | TypeId::RigidTypeParameter(pid), ) - | TypeRef::Infer( + | TypeRef::Any( TypeId::TypeParameter(pid) | TypeId::RigidTypeParameter(pid), ) | TypeRef::Uni( @@ -109,7 +109,7 @@ impl<'a, 'b, 'c> TypeSpecializer<'a, 'b, 'c> { _ => value.force_as_mut(self.db), }, - TypeRef::Owned(id) | TypeRef::Infer(id) => { + TypeRef::Owned(id) | TypeRef::Any(id) => { TypeRef::Owned(self.specialize_type_id(id)) } TypeRef::Uni(id) => TypeRef::Uni(self.specialize_type_id(id)), diff --git a/types/src/test.rs b/types/src/test.rs index 8050b85d2..c63081e96 100644 --- a/types/src/test.rs +++ b/types/src/test.rs @@ -86,7 +86,7 @@ pub(crate) fn mutable_uni(id: TypeId) -> TypeRef { } pub(crate) fn infer(id: TypeId) -> TypeRef { - TypeRef::Infer(id) + TypeRef::Any(id) } pub(crate) fn immutable(id: TypeId) -> TypeRef {