X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index 4060db6..03d82b14 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -75,7 +75,7 @@ redef class Model # Collections of classes grouped by their short name private var mclasses_by_name = new MultiHashMap[String, MClass] - # Return all class named `name`. + # Return all classes named `name`. # # If such a class does not exist, null is returned # (instead of an empty array) @@ -103,6 +103,9 @@ redef class Model # The only null type var null_type = new MNullType(self) + # The only bottom type + var bottom_type: MBottomType = null_type.as_notnull + # Build an ordered tree with from `concerns` fun concerns_tree(mconcerns: Collection[MConcern]): ConcernsTree do var seen = new HashSet[MConcern] @@ -159,7 +162,7 @@ redef class MModule return self.in_importation <= mclass.intro_mmodule end - # Full hierarchy of introduced ans imported classes. + # Full hierarchy of introduced and imported classes. # # Create a new hierarchy got by flattening the classes for the module # and its imported modules. @@ -252,8 +255,8 @@ redef class MModule # The primitive type `String` var string_type: MClassType = self.get_primitive_class("String").mclass_type is lazy - # The primitive type `NativeString` - var native_string_type: MClassType = self.get_primitive_class("NativeString").mclass_type is lazy + # The primitive type `CString` + var c_string_type: MClassType = self.get_primitive_class("CString").mclass_type is lazy # A primitive type of `Array` fun array_type(elt_type: MType): MClassType do return array_class.get_mtype([elt_type]) @@ -301,14 +304,14 @@ redef class MModule cladef.add_in_hierarchy return c end - print("Fatal Error: no primitive class {name} in {self}") + print_error("Fatal Error: no primitive class {name} in {self}") exit(1) abort end if cla.length != 1 then var msg = "Fatal Error: more than one primitive class {name} in {self}:" for c in cla do msg += " {c.full_name}" - print msg + print_error msg #exit(1) end return cla.first @@ -327,7 +330,7 @@ redef class MModule if res == null then res = mprop else if res != mprop then - print("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}") + print_error("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}") abort end end @@ -603,7 +606,7 @@ class MClassDef # ENSURE: `bound_mtype.mclass == self.mclass` var bound_mtype: MClassType - redef var location: Location + redef var location redef fun visibility do return mclass.visibility @@ -720,8 +723,11 @@ class MClassDef # All properties introduced by the classdef var intro_mproperties = new Array[MProperty] - # All property definitions in the class (introductions and redefinitions) + # All property introductions and redefinitions in `self` (not inheritance). var mpropdefs = new Array[MPropDef] + + # All property introductions and redefinitions (not inheritance) in `self` by its associated property. + var mpropdefs_by_property = new HashMap[MProperty, MPropDef] end # A global static type @@ -832,19 +838,19 @@ abstract class MType end #print "4.is {sub} a {sup}? <- no more resolution" - if sub isa MBottomType then + if sub isa MBottomType or sub isa MErrorType then return true end - assert sub isa MClassType else print "{sub} 3 # # Formal types have a depth of 1. + # Only `MClassType` and `MFormalType` nodes are counted. fun depth: Int do return 1 @@ -1131,6 +1154,7 @@ abstract class MType # * H[G[A], B] -> 4 # # Formal types have a length of 1. + # Only `MClassType` and `MFormalType` nodes are counted. fun length: Int do return 1 @@ -1197,7 +1221,7 @@ class MClassType redef fun need_anchor do return false - redef fun anchor_to(mmodule: MModule, anchor: MClassType): MClassType + redef fun anchor_to(mmodule, anchor): MClassType do return super.as(MClassType) end @@ -1349,6 +1373,24 @@ class MGenericType return true end + redef fun is_ok + do + for t in arguments do if not t.is_ok then return false + return super + end + + redef fun is_legal_in(mmodule, anchor) + do + var mtype + if need_anchor then + assert anchor != null + mtype = anchor_to(mmodule, anchor) + else + mtype = self + end + if not mtype.is_ok then return false + return mtype.is_subtype(mmodule, null, mtype.mclass.intro.bound_mtype) + end redef fun depth do @@ -1392,9 +1434,11 @@ class MVirtualType redef fun model do return self.mproperty.intro_mclassdef.mmodule.model - redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType + redef fun lookup_bound(mmodule, resolved_receiver) do - return lookup_single_definition(mmodule, resolved_receiver).bound or else new MBottomType(model) + # There is two possible invalid cases: the vt does not exists in resolved_receiver or the bound is broken + if not resolved_receiver.has_mproperty(mmodule, mproperty) then return new MErrorType(model) + return lookup_single_definition(mmodule, resolved_receiver).bound or else new MErrorType(model) end private fun lookup_single_definition(mmodule: MModule, resolved_receiver: MType): MVirtualTypeDef @@ -1430,7 +1474,7 @@ class MVirtualType var prop = lookup_single_definition(mmodule, resolved_receiver) var res = prop.bound - if res == null then return new MBottomType(model) + if res == null then return new MErrorType(model) # Recursively lookup the fixed result res = res.lookup_fixed(mmodule, resolved_receiver) @@ -1451,6 +1495,9 @@ class MVirtualType do if not cleanup_virtual then return self assert can_resolve_for(mtype, anchor, mmodule) + + if mproperty.is_selftype then return mtype + # self is a virtual type declared (or inherited) in mtype # The point of the function it to get the bound of the virtual type that make sense for mtype # But because mtype is maybe a virtual/formal type, we need to get a real receiver first @@ -1552,7 +1599,8 @@ class MParameterType return res end end - abort + # Cannot found `self` in `resolved_receiver` + return new MErrorType(model) end # A PT is fixed when: @@ -1665,6 +1713,10 @@ abstract class MProxyType return self.mtype.can_resolve_for(mtype, anchor, mmodule) end + redef fun is_ok do return mtype.is_ok + + redef fun is_legal_in(mmodule, anchor) do return mtype.is_legal_in(mmodule, anchor) + redef fun lookup_fixed(mmodule, resolved_receiver) do var t = mtype.lookup_fixed(mmodule, resolved_receiver) @@ -1763,7 +1815,7 @@ class MNullType redef fun c_name do return "null" redef fun as_nullable do return self - redef var as_notnull = new MBottomType(model) is lazy + redef var as_notnull: MBottomType = new MBottomType(model) is lazy redef fun need_anchor do return false redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self redef fun can_resolve_for(mtype, anchor, mmodule) do return true @@ -1778,9 +1830,10 @@ end # The special universal most specific type. # # This type is intended to be only used internally for type computation or analysis and should not be exposed to the user. -# The bottom type can de used to denote things that are absurd, dead, or the absence of knowledge. +# The bottom type can de used to denote things that are dead (no instance). # # Semantically it is the singleton `null.as_notnull`. +# Is also means that `self.as_nullable == null`. class MBottomType super MType redef var model @@ -1800,6 +1853,31 @@ class MBottomType redef fun collect_mtypes(mmodule) do return new HashSet[MClassType] end +# A special type used as a silent error marker when building types. +# +# This type is intended to be only used internally for type operation and should not be exposed to the user. +# The error type can de used to denote things that are conflicting or inconsistent. +# +# Some methods on types can return a `MErrorType` to denote a broken or a conflicting result. +# Use `is_ok` to check if a type is (or contains) a `MErrorType` . +class MErrorType + super MType + redef var model + redef fun to_s do return "error" + redef fun full_name do return "error" + redef fun c_name do return "error" + redef fun need_anchor do return false + redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self + redef fun can_resolve_for(mtype, anchor, mmodule) do return true + redef fun is_ok do return false + + redef fun collect_mclassdefs(mmodule) do return new HashSet[MClassDef] + + redef fun collect_mclasses(mmodule) do return new HashSet[MClass] + + redef fun collect_mtypes(mmodule) do return new HashSet[MClassType] +end + # A signature of a method class MSignature super MType @@ -2053,14 +2131,27 @@ abstract class MProperty #print "select prop {mproperty} for {mtype} in {self}" # First, select all candidates var candidates = new Array[MPROPDEF] - for mpropdef in self.mpropdefs do - # If the definition is not imported by the module, then skip - if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue - # If the definition is not inherited by the type, then skip - if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue - # Else, we keep it - candidates.add(mpropdef) + + # Here we have two strategies: iterate propdefs or iterate classdefs. + var mpropdefs = self.mpropdefs + if mpropdefs.length <= 1 or mpropdefs.length < mtype.collect_mclassdefs(mmodule).length then + # Iterate on all definitions of `self`, keep only those inherited by `mtype` in `mmodule` + for mpropdef in mpropdefs do + # If the definition is not imported by the module, then skip + if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue + # If the definition is not inherited by the type, then skip + if not mtype.is_subtype(mmodule, null, mpropdef.mclassdef.bound_mtype) then continue + # Else, we keep it + candidates.add(mpropdef) + end + else + # Iterate on all super-classdefs of `mtype`, keep only the definitions of `self`, if any. + for mclassdef in mtype.collect_mclassdefs(mmodule) do + var p = mclassdef.mpropdefs_by_property.get_or_null(self) + if p != null then candidates.add p + end end + # Fast track for only one candidate if candidates.length <= 1 then self.lookup_definitions_cache[mmodule, mtype] = candidates @@ -2136,7 +2227,7 @@ abstract class MProperty end end if res.is_empty then - print "All lost! {candidates.join(", ")}" + print_error "All lost! {candidates.join(", ")}" # FIXME: should be abort! end return res @@ -2247,6 +2338,9 @@ class MVirtualTypeProp # The formal type associated to the virtual type property var mvirtualtype = new MVirtualType(self) + + # Is `self` the special virtual type `SELF`? + var is_selftype: Bool is lazy do return name == "SELF" end # A definition of a property (local property) @@ -2277,6 +2371,7 @@ abstract class MPropDef do mclassdef.mpropdefs.add(self) mproperty.mpropdefs.add(self) + mclassdef.mpropdefs_by_property[mproperty] = self if mproperty.intro_mclassdef == mclassdef then assert not isset mproperty._intro mproperty.intro = self