Skip to content

Commit aecd0ab

Browse files
committed
Merged origin/dev into dev
2 parents a0729b0 + 7f06307 commit aecd0ab

File tree

3 files changed

+83
-2
lines changed

3 files changed

+83
-2
lines changed

src/ddperror/codes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const (
5757
SEM_GENERIC_FUNCTION_BODY_UNDEFINED // a generic function was declared without a definition
5858
SEM_ERROR_INSTANTIATING_GENERIC_FUNCTION // an error occured while instantiating a generic function
5959
SEM_CANNOT_INSTANTIATE_NON_GENERIC_TYPE // a non-generic type was given with type parameters
60+
SEM_UNABLE_TO_UNIFY_FIELD_TYPES // for a generic struct alias not all typeparamters could be unified
6061
)
6162

6263
// type error codes

src/parser/declarations.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,12 +906,19 @@ func (p *parser) validateStructAlias(aliasTokens []token.Token, fields []*ast.Va
906906

907907
nameTypeMap := make(map[string]ddptypes.ParameterType, len(fields)) // map that holds the parameter names contained in the alias and their corresponding type
908908
args := make(map[string]ddptypes.Type, len(fields)) // the arguments of the alias
909+
genericUnifiedMap := make(map[string]bool, len(fields)*2) // holds wether a generic type is unified
909910
for _, v := range fields {
910911
nameTypeMap[v.Name()] = ddptypes.ParameterType{
911912
Type: v.Type,
912913
IsReference: false, // fields are never references
913914
}
914915
args[v.Name()] = v.Type
916+
genericTypes, _ := ddptypes.CastDeeplyNestedGenerics(v.Type)
917+
for _, typ := range genericTypes {
918+
if _, ok := genericUnifiedMap[typ.Name]; !ok {
919+
genericUnifiedMap[typ.Name] = v.InitVal != nil
920+
}
921+
}
915922
}
916923
// validate that each parameter is contained in the alias once at max
917924
// and fill in the AliasInfo
@@ -932,6 +939,12 @@ func (p *parser) validateStructAlias(aliasTokens []token.Token, fields []*ast.Va
932939

933940
if argTyp, ok := nameTypeMap[k]; ok {
934941
aliasTokens[i].AliasInfo = &argTyp
942+
943+
genericTypes, _ := ddptypes.CastDeeplyNestedGenerics(argTyp.Type)
944+
for _, typ := range genericTypes {
945+
genericUnifiedMap[typ.Name] = true
946+
}
947+
935948
delete(nameTypeMap, k)
936949
} else {
937950
err := ddperror.New(ddperror.SEM_ALIAS_BAD_ARGS, ddperror.LEVEL_ERROR,
@@ -942,6 +955,17 @@ func (p *parser) validateStructAlias(aliasTokens []token.Token, fields []*ast.Va
942955
return &err, nil
943956
}
944957
}
958+
959+
for typ, wasUnified := range genericUnifiedMap {
960+
if !wasUnified {
961+
err := ddperror.New(ddperror.SEM_UNABLE_TO_UNIFY_FIELD_TYPES, ddperror.LEVEL_ERROR,
962+
token.NewRange(&aliasTokens[len(aliasTokens)-1], &aliasTokens[len(aliasTokens)-1]),
963+
fmt.Sprintf("Der generische Typ %s konnte nicht unifiziert werden", typ),
964+
p.module.FileName,
965+
)
966+
return &err, nil
967+
}
968+
}
945969
return nil, args
946970
}
947971

src/parser/declarations_test.go

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,8 +602,7 @@ Wir nennen die generische Kombination aus
602602
dem T y,
603603
dem R z,
604604
der R Liste l,
605-
eine Struktur, und erstellen sie so:
606-
"Struktur"
605+
eine Struktur."
607606
`),
608607
})
609608

@@ -614,3 +613,60 @@ eine Struktur, und erstellen sie so:
614613
assert.IsType(&ddptypes.GenericStructType{}, decl.Type)
615614
assert.Equal([]ddptypes.GenericType{{Name: "T"}, {Name: "R"}}, decl.Type.(*ddptypes.GenericStructType).GenericTypes)
616615
}
616+
617+
func TestValidateStructAlias(t *testing.T) {
618+
assert := assert.New(t)
619+
620+
given := createParser(t, parser{})
621+
622+
alias := scanAlias(t, `foo <a> <b>`, map[string]ddptypes.ParameterType{
623+
"a": {Type: ddptypes.ZAHL},
624+
"b": {Type: ddptypes.ZAHL},
625+
})
626+
err, _ := given.validateStructAlias(alias.GetTokens(), []*ast.VarDecl{
627+
{NameTok: token.Token{Literal: "a"}, Type: ddptypes.ZAHL},
628+
{NameTok: token.Token{Literal: "b"}, Type: ddptypes.ZAHL},
629+
})
630+
assert.Nil(err)
631+
632+
alias = scanAlias(t, `foo <a>`, map[string]ddptypes.ParameterType{
633+
"a": {Type: ddptypes.ZAHL},
634+
"b": {Type: ddptypes.ZAHL},
635+
})
636+
err, _ = given.validateStructAlias(alias.GetTokens(), []*ast.VarDecl{
637+
{NameTok: token.Token{Literal: "a"}, Type: ddptypes.ZAHL},
638+
{NameTok: token.Token{Literal: "b"}, Type: ddptypes.ZAHL},
639+
})
640+
assert.Nil(err)
641+
642+
alias = scanAlias(t, `foo <a> <b>`, map[string]ddptypes.ParameterType{
643+
"a": {Type: ddptypes.GenericType{Name: "T"}},
644+
"b": {Type: ddptypes.GenericType{Name: "R"}},
645+
})
646+
err, _ = given.validateStructAlias(alias.GetTokens(), []*ast.VarDecl{
647+
{NameTok: token.Token{Literal: "a"}, Type: ddptypes.GenericType{Name: "T"}},
648+
{NameTok: token.Token{Literal: "b"}, Type: ddptypes.GenericType{Name: "R"}},
649+
})
650+
assert.Nil(err)
651+
652+
alias = scanAlias(t, `foo <a>`, map[string]ddptypes.ParameterType{
653+
"a": {Type: ddptypes.GenericType{Name: "T"}},
654+
"b": {Type: ddptypes.GenericType{Name: "R"}},
655+
})
656+
err, _ = given.validateStructAlias(alias.GetTokens(), []*ast.VarDecl{
657+
{NameTok: token.Token{Literal: "a"}, Type: ddptypes.GenericType{Name: "T"}},
658+
{NameTok: token.Token{Literal: "b"}, Type: ddptypes.GenericType{Name: "R"}},
659+
})
660+
assert.NotNil(err)
661+
assert.Equal(ddperror.SEM_UNABLE_TO_UNIFY_FIELD_TYPES, err.Code)
662+
663+
alias = scanAlias(t, `foo <a>`, map[string]ddptypes.ParameterType{
664+
"a": {Type: ddptypes.GenericType{Name: "T"}},
665+
"b": {Type: ddptypes.GenericType{Name: "R"}},
666+
})
667+
err, _ = given.validateStructAlias(alias.GetTokens(), []*ast.VarDecl{
668+
{NameTok: token.Token{Literal: "a"}, Type: ddptypes.GenericType{Name: "T"}},
669+
{NameTok: token.Token{Literal: "b"}, Type: ddptypes.GenericType{Name: "R"}, InitVal: &ast.IntLit{}},
670+
})
671+
assert.Nil(err)
672+
}

0 commit comments

Comments
 (0)