package sema
import (
"github.com/marzeq/qk/parser"
"github.com/marzeq/qk/types"
)
type aliasState int
const (
aliasUnseen aliasState = iota
aliasResolving
aliasResolved
)
type aliasInfo struct {
node *parser.TypeAliasNode
state aliasState
resolved types.Type
}
func (a *Analyser) resolveAlias(info *aliasInfo, node parser.Node, indirect bool) types.Type {
switch info.state {
case aliasResolving:
named, namedType := info.node.Type.(*parser.NamedTypeNode)
genericApplication := namedType && len(named.TypeArguments) != 0
if indirect || genericApplication {
if _, ok := info.node.Type.(*parser.TraitTypeNode); ok && !info.node.Transparent {
return types.TraitType{Module: a.currentMod, Name: info.node.Name}
}
return &types.AliasRef{Module: a.currentMod, Name: info.node.Name, Target: &info.resolved}
}
a.errorf(node, "circular type definition detected")
return types.ErrorType{}
case aliasResolved:
return info.node.Symbol.TypeInfo
}
info.state = aliasResolving
previousTraitContext := a.resolvingTraitMethodTypes
a.resolvingTraitMethodTypes = false
// Preserve the indirection that led into this named type. A recursive
// reference may pass through intermediate aliases before returning to the
// type whose storage is pointer-backed. Completeness validation still
// rejects cycles that ultimately contain values inline.
resolved := a.resolveTypeNodeAt(info.node.Type, indirect)
a.resolvingTraitMethodTypes = previousTraitContext
if trait, ok := resolved.(types.TraitType); ok && !info.node.Transparent {
trait.Module = a.currentMod
trait.Name = info.node.Name
resolved = trait
a.nominalTraits[trait.Module+":"+trait.Name] = trait
a.registerTraitDefaults(info.node, trait, a.currentRoot)
} else if !info.node.Transparent {
resolved = types.DefinedType{Module: a.currentMod, Name: info.node.Name, Underlying: resolved}
a.concreteTypes[a.currentMod+":"+info.node.Name] = resolved
}
info.node.Symbol.TypeInfo = resolved
info.resolved = resolved
info.state = aliasResolved
return resolved
}