-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Composite literal inference #704
Changes from all commits
2e80b8d
d8a5902
5a19f16
14bb2a9
56e335a
d4bdd0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -435,6 +435,14 @@ | |
} | ||
return nil | ||
} | ||
case *syntax.Ident: | ||
// names? | ||
if n, ok := Predefined[n.String()]; ok { | ||
return n | ||
} | ||
if n.String() == "infinity" { | ||
return Predefined["float"] | ||
} | ||
case *syntax.BinaryExpr: | ||
switch n.Op.Kind() { | ||
case syntax.LT, syntax.GT, syntax.LE, syntax.GE, syntax.EQ, syntax.NE, syntax.AND, syntax.OR, syntax.XOR: | ||
|
@@ -448,6 +456,19 @@ | |
return Predefined["integer"] | ||
case syntax.SHL, syntax.SHR, syntax.ROL, syntax.ROR: | ||
return TypeOf(n.X) | ||
case syntax.ASSIGN: | ||
// Investigate: Label on the left, omit on the right, Maps | ||
if n.Y.FirstTok().Kind() == syntax.OMIT { | ||
if t := TypeOf(n.X); t != nil { | ||
return t | ||
} else { | ||
return Predefined["boolean"] | ||
} | ||
} | ||
if X, ok := n.X.(*syntax.IndexExpr); ok && X.X == nil && TypeOf(X.Index) != Predefined["integer"] { | ||
return &MapType{From: TypeOf(X.Index), To: TypeOf(n.Y)} | ||
} | ||
return TypeOf(n.Y) | ||
} | ||
case *syntax.UnaryExpr: | ||
switch n.Op.Kind() { | ||
|
@@ -458,6 +479,175 @@ | |
case syntax.INC, syntax.DEC: | ||
return Predefined["integer"] | ||
} | ||
case *syntax.ParenExpr: | ||
// different length? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI: |
||
if len(n.List) == 1 { | ||
return TypeOf(n.List[0]) | ||
} | ||
case *syntax.IndexExpr: | ||
if n.X == nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please comments explaining the conditions. Short examples are okay. |
||
return TypeOf(n.Index) | ||
} else if X, ok := TypeOf(n.X).(*ListType); ok { | ||
return X.ElementType | ||
} else { | ||
return TypeOf(n.X).(*MapType).From | ||
} | ||
} | ||
case *syntax.CompositeLiteral: | ||
fields := make([]Field, len(n.List)) | ||
typeList := make([]Type, len(n.List)) | ||
isRecord := false | ||
|
||
for i, v := range n.List { | ||
typeList[i] = TypeOf(v) | ||
fields[i].Type = typeList[i] | ||
if v, ok := v.(*syntax.BinaryExpr); ok && v.Op.Kind() == syntax.ASSIGN && v.Y.FirstTok().Kind() == syntax.OMIT { | ||
fields[i].Optional = true | ||
isRecord = true | ||
} else { | ||
fields[i].Optional = false | ||
} | ||
} | ||
if len(fields) == 0 { | ||
return &ListType{Kind: RecordOf} | ||
} | ||
Comment on lines
+511
to
+513
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move this condition to the top of the case-block to improve the flow when reading. Also, you can remove one indirection. Write |
||
if t := mostSpecificCommonTypeOfArray(typeList...); isRecord || t == Predefined["any"] { | ||
t = &StructuredType{Kind: Record, Fields: fields} | ||
return t | ||
// Map vs Record of Maps? | ||
} else if _, ok := t.(*MapType); ok { | ||
return t | ||
} else { | ||
return &ListType{Kind: RecordOf, ElementType: t} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func mostSpecificCommonTypeOfArray(types ...Type) Type { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please write a documentation comment for this function. |
||
if len(types) == 0 { | ||
return Predefined["any"] | ||
} | ||
result := types[0] | ||
if len(types) == 1 || result == Predefined["any"] { | ||
return result | ||
} | ||
for _, v := range types[1:] { | ||
result = mostSpecificCommonTypeOf2(result, v) | ||
if result == Predefined["any"] { | ||
break | ||
} | ||
} | ||
return result | ||
} | ||
|
||
func mostSpecificCommonTypeOf2(type1 Type, type2 Type) Type { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Has |
||
if type1 == type2 { | ||
return type1 | ||
} | ||
if t := isSuper(type1, type2); t != nil { | ||
return t | ||
} | ||
// Is there another Type that the two share? | ||
return Predefined["any"] | ||
} | ||
|
||
func isSuper(type1 Type, type2 Type) Type { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Before merging you should rename and document this function. |
||
if type1 == Predefined["any"] || type2 == Predefined["any"] { | ||
return Predefined["any"] | ||
} | ||
switch type1 := type1.(type) { | ||
case *PrimitiveType: | ||
if type2, ok := type2.(*PrimitiveType); !ok { | ||
return nil | ||
} else { | ||
if type1.Kind == type2.Kind { | ||
if type1.ValueConstraints == nil { | ||
return type1 | ||
} | ||
if type2.ValueConstraints == nil { | ||
return type2 | ||
} | ||
// ToDo: Add more ConstraintChecks | ||
} | ||
return nil | ||
} | ||
case *ListType: | ||
if type2, ok := type2.(*ListType); !ok { | ||
return nil | ||
} else { | ||
if type1.Kind == type2.Kind { | ||
if type1.ElementType == type2.ElementType { | ||
return type1 | ||
} | ||
if isString(type1.Kind) { | ||
// Check Constraints | ||
return nil | ||
} | ||
// check ElementType (Array RecordOf SetOf) | ||
superElement := isSuper(type1.ElementType, type2.ElementType) | ||
if superElement == type1.ElementType { | ||
return type1 | ||
} | ||
if superElement == type2.ElementType { | ||
return type2 | ||
} | ||
return nil | ||
} | ||
switch type1.Kind { | ||
case Hexstring, Octetstring, Bitstring, SetOf: | ||
return nil | ||
case Charstring: | ||
if type2.Kind == UniversalCharstring { | ||
// check Constraints | ||
return type2 | ||
} | ||
return nil | ||
case UniversalCharstring: | ||
if type2.Kind == Charstring { | ||
// check Constraints | ||
return type1 | ||
} | ||
return nil | ||
case RecordOf: | ||
if type2.Kind == Array { | ||
// check ElementType and Constraints | ||
return type1 | ||
} | ||
return nil | ||
case Array: | ||
if type2.Kind == RecordOf { | ||
// check ElementType and Constraints | ||
return type2 | ||
} | ||
return nil | ||
} | ||
} | ||
case *StructuredType: | ||
if type2, ok := type2.(*StructuredType); !ok { | ||
return nil | ||
} else { | ||
if type1.Kind == type2.Kind && len(type1.Fields) == len(type2.Fields) { | ||
for i, f := range type1.Fields { | ||
if f.Optional == type2.Fields[i].Optional && isSuper(f.Type, type2.Fields[i].Type) == f.Type { | ||
continue | ||
} else { | ||
return nil | ||
} | ||
} | ||
return type1 | ||
} | ||
} | ||
case *MapType: | ||
if type2, ok := type2.(*MapType); !ok || type1.From != type2.From { | ||
return nil | ||
} else { | ||
if superTo := isSuper(type1.To, type2.To); superTo == type1.To { | ||
return type1 | ||
} else if superTo == type2.To { | ||
return type2 | ||
} | ||
} | ||
} | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you check if this condition is ever true?
At least it should never be true, because the
infinity
token is supposed to asyntax.ValueLiteral
(liketrue
,inconc
, ...) and notsyntax.Ident
.If it es ever true it must be a bug in the parser, which needs fixing.