nullable: type, compile and test 'isset _attr'
[nit.git] / src / syntax / typing.nit
index 921ea14..6717511 100644 (file)
@@ -1001,6 +1001,19 @@ redef class AAttrReassignExpr
        end
 end
 
+redef class AIssetAttrExpr
+       redef meth after_typing(v)
+       do
+               do_typing(v)
+               if prop == null then return
+               if attr_type.is_nullable then
+                       v.error(self, "Error: isset on a nullable attribute.")
+               end
+               _stype = v.type_bool
+               _is_typed = true
+       end
+end
+
 class AAbsAbsSendExpr
 special PExpr
        # The signature of the called property
@@ -1313,6 +1326,20 @@ redef class AEqExpr
                n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
                        v.warning(self, "Warning: comparaison between null and a non nullable value.")
                end
+
+               if n_expr.stype isa MMTypeNone then
+                       try_to_isa(v, n_expr2)
+               else if n_expr2.stype isa MMTypeNone then
+                       try_to_isa(v, n_expr)
+               end
+       end
+
+       private meth try_to_isa(v: TypingVisitor, n: PExpr)
+       do
+               var variable = n.its_variable
+               if variable != null then
+                       _if_false_variable_ctx = v.variable_ctx.sub_with(self, variable, n.stype.as_notnull)
+               end
        end
 end
 redef class ANeExpr
@@ -1325,6 +1352,20 @@ redef class ANeExpr
                n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
                        v.warning(self, "Warning: comparaison between null and a non nullable value.")
                end
+
+               if n_expr.stype isa MMTypeNone then
+                       try_to_isa(v, n_expr2)
+               else if n_expr2.stype isa MMTypeNone then
+                       try_to_isa(v, n_expr)
+               end
+       end
+
+       private meth try_to_isa(v: TypingVisitor, n: PExpr)
+       do
+               var variable = n.its_variable
+               if variable != null then
+                       _if_true_variable_ctx = v.variable_ctx.sub_with(self, variable, n.stype.as_notnull)
+               end
        end
 end
 redef class ALtExpr
@@ -1550,6 +1591,18 @@ special PExpr
                        v.warning(self, "Warning: Expression is already a {ttype}.")
                else if etype < ttype then
                        v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.")
+               else if etype.is_nullable and etype.as_notnull == ttype then
+                       if ttype isa MMTypeFormal and ttype.bound.is_nullable then
+                               # No warning in this case since with
+                               #   type T: nullable A
+                               #   var x: nullable T
+                               # 'x.as(not null)' != 'x.as(T)'
+                               # 'x != null' != 'x isa T'
+                       else if self isa AIsaExpr then
+                               v.warning(self, "Warning: Prefer '!= null'.")
+                       else
+                               v.warning(self, "Warning: Prefer '.as(not null)'.")
+                       end
                end
        end
 end