abort
end
+ # Is the virtual type fixed for a given resolved_receiver?
+ fun is_fixed(mmodule: MModule, resolved_receiver: MType): Bool
+ do
+ assert not resolved_receiver.need_anchor
+ var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver)
+ if props.is_empty then
+ abort
+ end
+ for p in props do
+ if p.as(MVirtualTypeDef).is_fixed then return true
+ end
+ return false
+ end
+
redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
do
assert can_resolve_for(mtype, anchor, mmodule)
if resolved_reciever.as(MClassType).mclass.kind == enum_kind then return res
# If the resolved type isa MVirtualType, it means that self was bound to it, and cannot be unbound. self is just fixed. so return the resolution.
if res isa MVirtualType then return res
+ # If we are final, just return the resolution
+ if is_fixed(mmodule, resolved_reciever) then return res
# It the resolved type isa intern class, then there is no possible valid redefinition is any potentiel subclass. self is just fixed. so simply return the resolution
if res isa MClassType and res.mclass.kind == enum_kind then return res
# TODO: Add 'fixed' virtual type in the specification.
# The bound of the virtual type
var bound: nullable MType writable = null
+
+ # Is the bound fixed?
+ var is_fixed writable = false
end
# A kind of class.
self.mpropdef = mpropdef
modelbuilder.mpropdef2npropdef[mpropdef] = self
set_doc(mpropdef)
+
+ var atfixed = get_single_annotation("fixed", modelbuilder)
+ if atfixed != null then
+ mpropdef.is_fixed = true
+ end
end
redef fun build_signature(modelbuilder)
modelbuilder.check_visibility(n_type, bound, mpropdef)
- # Fast case: the bound is not a formal type
- if not bound isa MVirtualType then return
-
var mclassdef = mpropdef.mclassdef
var mmodule = mclassdef.mmodule
var anchor = mclassdef.bound_mtype
- # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
- var seen = [self.mpropdef.mproperty.mvirtualtype]
- loop
- if seen.has(bound) then
+ # Check circularity
+ if bound isa MVirtualType then
+ # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
+ var seen = [self.mpropdef.mproperty.mvirtualtype]
+ loop
+ if seen.has(bound) then
+ seen.add(bound)
+ modelbuilder.error(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
+ return
+ end
seen.add(bound)
- modelbuilder.error(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
- return
+ var next = bound.lookup_bound(mmodule, anchor)
+ if not next isa MVirtualType then break
+ bound = next
+ end
+ end
+
+ # Check redefinitions
+ bound = mpropdef.bound.as(not null)
+ for p in mpropdef.mproperty.lookup_super_definitions(mmodule, anchor) do
+ var supbound = p.bound.as(not null)
+ if p.is_fixed then
+ modelbuilder.error(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
+ break
+ end
+ if p.mclassdef.mclass == mclassdef.mclass then
+ # Still a warning to pass existing bad code
+ modelbuilder.warning(n_type, "Redef Error: a virtual type cannot be refined.")
+ break
+ end
+ if not bound.is_subtype(mmodule, anchor, supbound) then
+ modelbuilder.error(n_type, "Redef Error: Wrong bound type. Found {bound}, expected a subtype of {supbound}, as in {p}.")
+ break
end
- seen.add(bound)
- var next = bound.lookup_bound(mmodule, anchor)
- if not next isa MVirtualType then break
- bound = next
end
end
end
import kernel
class A[T]
- type U: Object
+ type U: nullable Object
fun testT(o: Object): Bool do return o isa T
fun testU(o: Object): Bool do return o isa U
end
class A[X]
- type T: Object
+ type T: nullable Object
fun foo(o: Object): Bool do
return o isa T
class C[X, Y]
super B[X]
- redef type T: Y
+ redef type T: X
end
var a = new A[Object]
assert b.bar(true)
var c = new C[Object, B[Object]]
-assert not c.foo(new A[Object])
+assert c.foo(new A[Object])
assert c.foo(new B[Object])
assert c.foo(new C[Object, B[Object]])
end
class A[T, U]
- type V: Object
+ type V: nullable Object
fun foo: Triple[T, U, V] do
var triple = new Triple[T, U, V]
var a = new A[String, Int]
-assert a.foo isa Triple[String, Int, Object]
+assert a.foo isa Triple[String, Int, nullable Object]
var b = new B[String]
assert b.foo isa Triple[String, String, String]
import base_minimal
class A[X]
- type T: Object
+ type T: nullable Object
fun foo(o: Object): Bool do
return o isa T
class C[X]
super B[X]
- redef type T: C[B[X]]
+ redef type T: C[X]
end
var a = new A[Object]
var c = new C[Object]
assert not c.foo(new A[Object])
assert not c.foo(new B[Object])
-assert not c.foo(new C[Object])
+assert c.foo(new C[Object])
assert c.foo(new C[B[Object]])
assert c.foo(new C[B[Bool]])
--- /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 kernel
+
+interface A
+ type V1: Object
+ fun v1(v: V1): V1 do return v
+ type V2: Object
+ fun v2(v: V2): V2 do return v
+end
+interface B
+ super A
+ redef type V1: Discrete
+ redef type V2: Discrete is fixed
+end
+class C
+ super B
+
+ # Because of the workaround, there is no simple way to see the subtype relation
+ #alt1#redef fun v1(v: Discrete): Discrete do return v
+ redef fun v2(v: Discrete): Discrete do return v
+end
+
+var c: A = new C
+c.v1(1).output
+c.v1(2).output
import kernel
interface Number
- type OTHER: Number
+ type OTHE: Number
+ type OTHE2: Int
+ type OTHE3: Object is fixed
end
-
redef class Int
super Number
- redef type OTHER: Int
+ redef type OTHE: Int
+ #alt1#redef type OTHE2: Number
+ #alt2#redef type OTHE3: Int
end
base_isa_vt_gen1.nit:30,10--34: Warning: Expression is already a Triple[A#0, A#1, V].
-base_isa_vt_gen1.nit:54,8--43: Warning: Expression is already a Triple[String, Int, Object].
+base_isa_vt_gen1.nit:54,8--52: Warning: Expression is already a Triple[String, Int, nullable Object].
base_isa_vt_gen1.nit:57,8--46: Warning: Expression is already a Triple[String, String, String].
base_isa_vt_gen1.nit:60,8--48: Warning: Expression is already a Triple[String, String, B[String]].
base_isa_vt_gen1.nit:63,8--46: Warning: Expression is already a Triple[String, String, String].
+base_virtual_type4.nit:20,16: Redef Error: a virtual type cannot be refined.
1
+alt/base_virtual_type4_alt1.nit:20,16: Redef Error: a virtual type cannot be refined.
alt/base_virtual_type4_alt1.nit:24,7--11: Type error: expected nullable U, got T
--- /dev/null
+alt/base_virtual_type_fixed_alt1.nit:32,15--25: Redef Error: Wrong type for parameter `v'. found Discrete, expected V1 as in base_virtual_type_fixed_alt1#A#v1.
+alt/base_virtual_type_fixed_alt1.nit:32,29--36: Redef Error: Wrong return type. found Discrete, expected V1 as in base_virtual_type_fixed_alt1#A#v1.
-base_virtual_type_redef.nit:24,13--17: Ambigous property name 'OTHER' for Int; conflict between standard::kernel::Comparable::OTHER and base_virtual_type_redef::Number::OTHER
--- /dev/null
+alt/base_virtual_type_redef_alt1.nit:26,20--25: Redef Error: Wrong bound type. Found Number, expected a subtype of Int, as in base_virtual_type_redef_alt1#Number#OTHE2.
--- /dev/null
+alt/base_virtual_type_redef_alt2.nit:26,2--27,22: Redef Error: Virtual type OTHE3 is fixed in super-class Number
+++ /dev/null
-Runtime error: Assert failed (base_isa_vt_gen3.nit:48)
--- /dev/null
+../lib/mnit_linux/linux_app.nit:28,16--31: Redef Error: a virtual type cannot be refined.
+../lib/mnit_linux/linux_app.nit:29,16--29: Redef Error: a virtual type cannot be refined.