From: Jean Privat Date: Wed, 8 Apr 2015 01:01:49 +0000 (+0700) Subject: Merge: Not null types X-Git-Tag: v0.7.4~37 X-Git-Url: http://nitlanguage.org Merge: Not null types In order to fix #86 and #1238 some preliminary work to solve remaining issues with the type system is needed. This PR is a step toward this goal. This introduce not-null types, that is a modifier to indicate that a type cannot contain null. Basically, this new modifier is almost useless because it is the semantic of all the types (except obviously null and nullable things). Except in one case: when one adapts a formal type whose bound is nullable. Before the PR, the semantic was the following ~~~nit class A[E: nullable Object] fun foo(e: E, o: nullable Object) do var o2 = o.as(not null) # the static type of o2 is `Object` print o2 # OK var e2 = e.as(not null) # the static type of e2 is still `E` because there is no `nullable` to remove print e2 # Error: expected Object, got E end end ~~~ Obviously, the issue was not that important because people managed to program complex things in Nit and I do not remember getting some complain about that particular issue. For the rare cases of this unexpected behavior, a workaround was possible: to cast on the non-nullable bound ~~~nit var e2 = e.as(Object) print e2 # OK ~~~ Nevertheless, the behavior was still buggy since type information was lost and not POLA. Moreover, `!= null` and `or else` did not have a workaround. So, this PR introduces a special new type-modifier for this case so that everything become sensible. ~~~nit var e2 = e.as(not null) # the static type of e2 is now `not null E` print e2 # OK ~~~ Moreover, a lot of local refactorisation was done in model.nit and typing.nit to clean and harmonize the code. So that independently of the new notnull modifier, the code is cleaner, some bugs where removed and some small features added, especially the detection of useless `or else`. Last, but not least, the `not null` thing is only an internal modifier and is not usable as a syntactic type construction (the grammar and the AST is unchanged); `not null` can however be shown to the programmer in messages. ~~~nit var e2 = e.as(not null) # the static type of e2 is now `not null E` var e3 = e2.as(not null) # << Warning: expression is not null, since it is a `not null E` >> ~~~ I could easily add `not null` as a specific syntactic construction since everything internally is ready. but 1. does this worth it?. 2. I do not want to conflict with #1243 that also change the grammar. As an example, is it useful to write the following? (currently refused but very easy to add after this PR) ~~~nit class A[E: nullable Object] fun foo(e: not null E): not null E do var x = e.to_s # no null pointer exception # ... return e end end var a = new A[nullable Int] var i = a.foo(5) ~~~ Pull-Request: #1244 Reviewed-by: Etienne M. Gagnon Reviewed-by: Lucas Bajolet Reviewed-by: Romain Chanoir Reviewed-by: Alexandre Terrasa --- dea37f057bd038e4f969fc1623e7a9464a685268 diff --cc src/semantize/typing.nit index 8e9e3ac,0634ee2..38a689a --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@@ -1133,10 -1162,8 +1170,10 @@@ redef class AOrElseExp var t = v.merge_types(self, [t1, t2]) if t == null then - t = v.mmodule.object_type + var c = v.get_mclass(self, "Object") + if c == null then return # forward error + t = c.mclass_type - if t2 isa MNullableType then + if v.can_be_null(t2) then t = t.as_nullable end #v.error(self, "Type Error: ambiguous type {t1} vs {t2}")