var nfd = nclassdef.n_formaldefs[i]
var nfdt = nfd.n_type
if nfdt != null then
- var bound = resolve_mtype(nclassdef, nfdt)
+ var bound = resolve_mtype_unchecked(nclassdef, nfdt)
if bound == null then return # Forward error
if bound.need_anchor then
# No F-bounds!
for nsc in nclassdef.n_superclasses do
specobject = false
var ntype = nsc.n_type
- var mtype = resolve_mtype(nclassdef, ntype)
+ var mtype = resolve_mtype_unchecked(nclassdef, ntype)
if mtype == null then continue # Skip because of error
if not mtype isa MClassType then
error(ntype, "Error: supertypes cannot be a formal type")
mclassdef.add_in_hierarchy
end
+ # Check unchecked ntypes
+ for nclassdef in nmodule.n_classdefs do
+ if nclassdef isa AStdClassdef then
+ # check bound of formal parameter
+ for nfd in nclassdef.n_formaldefs do
+ var nfdt = nfd.n_type
+ if nfdt != null and nfdt.mtype != null then
+ var bound = resolve_mtype(nclassdef, nfdt)
+ if bound == null then return # Forward error
+ end
+ end
+ # check declared super types
+ for nsc in nclassdef.n_superclasses do
+ var ntype = nsc.n_type
+ if ntype.mtype != null then
+ var mtype = resolve_mtype(nclassdef, ntype)
+ if mtype == null then return # Forward error
+ end
+ end
+ end
+
+ end
+
# TODO: Check that the super-class is not intrusive
# TODO: Check that the super-class is not already known (by transitivity)
# The mmodule used as context is `nclassdef.mmodule'
# In case of problem, an error is displayed on `ntype' and null is returned.
# FIXME: the name "resolve_mtype" is awful
- fun resolve_mtype(nclassdef: AClassdef, ntype: AType): nullable MType
+ fun resolve_mtype_unchecked(nclassdef: AClassdef, ntype: AType): nullable MType
do
var name = ntype.n_id.text
var mclassdef = nclassdef.mclassdef
end
res = prop.mvirtualtype
if ntype.n_kwnullable != null then res = res.as_nullable
+ ntype.mtype = res
return res
end
end
if mclassdef.parameter_names[i] == name then
res = mclassdef.mclass.mclass_type.arguments[i]
if ntype.n_kwnullable != null then res = res.as_nullable
+ ntype.mtype = res
return res
end
end
if arity == 0 then
res = mclass.mclass_type
if ntype.n_kwnullable != null then res = res.as_nullable
+ ntype.mtype = res
return res
else
var mtypes = new Array[MType]
for nt in ntype.n_types do
- var mt = resolve_mtype(nclassdef, nt)
+ var mt = resolve_mtype_unchecked(nclassdef, nt)
if mt == null then return null # Forward error
mtypes.add(mt)
end
res = mclass.get_mtype(mtypes)
if ntype.n_kwnullable != null then res = res.as_nullable
+ ntype.mtype = res
return res
end
end
return null
end
+ # Return the static type associated to the node `ntype'.
+ # `classdef' is the context where the call is made (used to understand formal types)
+ # The mmodule used as context is `nclassdef.mmodule'
+ # In case of problem, an error is displayed on `ntype' and null is returned.
+ # FIXME: the name "resolve_mtype" is awful
+ fun resolve_mtype(nclassdef: AClassdef, ntype: AType): nullable MType
+ do
+ var mtype = ntype.mtype
+ if mtype == null then mtype = resolve_mtype_unchecked(nclassdef, ntype)
+ if mtype == null then return null # Forward error
+
+ if ntype.checked_mtype then return mtype
+ if mtype isa MGenericType then
+ var mmodule = nclassdef.parent.as(AModule).mmodule.as(not null)
+ var mclassdef = nclassdef.mclassdef
+ var mclass = mtype.mclass
+ for i in [0..mclass.arity[ do
+ var bound = mclass.intro.bound_mtype.arguments[i]
+ var nt = ntype.n_types[i]
+ var mt = resolve_mtype(nclassdef, nt)
+ if mt == null then return null # forward error
+ if not mt.is_subtype(mmodule, mclassdef.bound_mtype, bound) then
+ error(nt, "Type error: expected {bound}, got {mt}")
+ return null
+ end
+ end
+ end
+ ntype.checked_mtype = true
+ return mtype
+ end
+
# Helper function to display an error on a node.
# Alias for `self.toolcontext.error(n.hot_location, text)'
fun error(n: ANode, text: String)
redef fun mvisibility do return private_visibility
end
+redef class AType
+ # The mtype associated to the node
+ var mtype: nullable MType = null
+
+ # Is the mtype a valid one?
+ var checked_mtype: Bool = false
+end
#
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import end
+
+interface Object
+end
+
+class A
+end
+
+class B
+ super A
+end
+
+class G[E:B]
+end
+
+class H[F:A]
+ #alt1 super G[F]
+ #alt2 var a: G[F]
+ #alt3 fun b: G[F] is abstract
+ #alt4 fun c(x: G[F]) is abstract
+end
+
+class I
+ type V: A
+ #alt5 var a: G[V]
+ #alt6 fun b: G[V] is abstract
+ #alt7 fun c(x: G[V]) is abstract
+end
+
+#alt8 class J[FF:G[A]]
+#alt8 end
+
+var a = new A
+var b = new B
+#alt9 var ga = new G[A]
+var gb = new G[B]
+var ha = new H[A]
+var hb = new H[B]
+var i = new I