| 1 | use System.Reflection |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | class Box |
|---|
| 5 | is abstract, partial |
|---|
| 6 | inherits Container<of IBoxMember> |
|---|
| 7 | implements IType, IParentSpace, INameSpaceMember, IBoxMember |
|---|
| 8 | """ |
|---|
| 9 | The abstract base class for: |
|---|
| 10 | * Class |
|---|
| 11 | * Interface |
|---|
| 12 | * Struct |
|---|
| 13 | These are collectively known as "boxes". |
|---|
| 14 | Note that of all the types, only Boxes can be generic. Which makes them special. |
|---|
| 15 | """ |
|---|
| 16 | |
|---|
| 17 | # TODO: need to override greatestCommonDenominatorWith() to handle base interfaces |
|---|
| 18 | |
|---|
| 19 | var _genericParams as List<of IType> # as in generic parameters |
|---|
| 20 | var _genericDef as Box? |
|---|
| 21 | var _constructedTypes as Dictionary<of String, Box>? |
|---|
| 22 | |
|---|
| 23 | var _baseClass as Class? |
|---|
| 24 | var _baseInterfaceProxies as List<of ITypeProxy> |
|---|
| 25 | var _baseInterfaces as List<of Interface> |
|---|
| 26 | |
|---|
| 27 | var _overloads as List<of MemberOverload> |
|---|
| 28 | var _nextPrivateSerialNumber = 1001 |
|---|
| 29 | |
|---|
| 30 | var _attribs as AttributeList |
|---|
| 31 | |
|---|
| 32 | var _invariants as List<of Expr> |
|---|
| 33 | var _testMethods as List<of TestMethod> |
|---|
| 34 | |
|---|
| 35 | var _nativeType as NativeType? |
|---|
| 36 | var _needScanNativeType as bool |
|---|
| 37 | var _membersToUnNil as String? |
|---|
| 38 | |
|---|
| 39 | cue init(token as IToken, idToken as IToken, name as String, paramList as List<of IType>, isNames as String*, attribs as AttributeList, baseInterfaceNodes as List<of ITypeProxy>, docString as String?) |
|---|
| 40 | base.init(token, name, isNames, docString) |
|---|
| 41 | _idToken = idToken |
|---|
| 42 | _attribs = attribs |
|---|
| 43 | _genericParams = paramList |
|---|
| 44 | for i in _genericParams.count |
|---|
| 45 | p = _genericParams[i] |
|---|
| 46 | if p inherits GenericParam |
|---|
| 47 | p.index = i |
|---|
| 48 | p.parentDefinition = this |
|---|
| 49 | _baseInterfaceProxies = baseInterfaceNodes |
|---|
| 50 | _baseInterfaces = List<of Interface>() |
|---|
| 51 | _overloads = List<of MemberOverload>() |
|---|
| 52 | _invariants = List<of Expr>() |
|---|
| 53 | _testMethods = List<of TestMethod>() |
|---|
| 54 | |
|---|
| 55 | def _initNativeType(t as NativeType) |
|---|
| 56 | ensure .needScanNativeType |
|---|
| 57 | _nativeType = t |
|---|
| 58 | _needScanNativeType = true |
|---|
| 59 | assert .compiler |
|---|
| 60 | .backEnd.scanGenericArgs(this) # convert any generic args from back-end form to Cobra data structures |
|---|
| 61 | |
|---|
| 62 | def addMinFields |
|---|
| 63 | base.addMinFields |
|---|
| 64 | .addField('didBindInh', .didBindInh) |
|---|
| 65 | .addField('isGeneric', .isGeneric) |
|---|
| 66 | .addField('isGenericDef', .isGenericDef) |
|---|
| 67 | .addField('needsConstruction', .needsConstruction) |
|---|
| 68 | |
|---|
| 69 | def addRefFields |
|---|
| 70 | base.addRefFields |
|---|
| 71 | .addField('genericDef', _genericDef) |
|---|
| 72 | .addField('baseClass', _baseClass) |
|---|
| 73 | .addField('nativeType', .nativeType) |
|---|
| 74 | |
|---|
| 75 | def addSubFields |
|---|
| 76 | base.addSubFields |
|---|
| 77 | .addField('genericParams', _genericParams) |
|---|
| 78 | .addField('baseInterfaces', _baseInterfaces) |
|---|
| 79 | .addField('baseInterfaceProxies', _baseInterfaceProxies) |
|---|
| 80 | |
|---|
| 81 | def toTraceString as String |
|---|
| 82 | sb = StringBuilder('[.getType.name]([.name], [.serialNum], ') |
|---|
| 83 | if _genericParams.count |
|---|
| 84 | sb.append('genericParams=[CobraCore.toTechString(_genericParams)], ') |
|---|
| 85 | if not .didBindInh, sb.append('not ') |
|---|
| 86 | sb.append('didBindInh, ') |
|---|
| 87 | if not .didBindInt, sb.append('not ') |
|---|
| 88 | sb.append('didBindInt, ') |
|---|
| 89 | sb.append('nativeType=[.nativeType]') |
|---|
| 90 | sb.append(')') |
|---|
| 91 | return sb.toString |
|---|
| 92 | |
|---|
| 93 | get attributes as AttributeList is override |
|---|
| 94 | return _attribs |
|---|
| 95 | |
|---|
| 96 | def allBaseTypes as Box* |
|---|
| 97 | require .didBindInh |
|---|
| 98 | if .baseClass |
|---|
| 99 | yield .baseClass to ! |
|---|
| 100 | for bt in .baseClass.allBaseTypes, yield bt |
|---|
| 101 | for bi in .baseInterfaces |
|---|
| 102 | yield bi |
|---|
| 103 | for bt in bi.allBaseTypes, yield bt |
|---|
| 104 | |
|---|
| 105 | def allMembers as IList<of IBoxMember> |
|---|
| 106 | imembers = List<of IBoxMember>() |
|---|
| 107 | members = List<of IBoxCodeMember>() |
|---|
| 108 | _allMembers(imembers, members) |
|---|
| 109 | _allExtensionMembers(imembers, members) |
|---|
| 110 | return imembers |
|---|
| 111 | |
|---|
| 112 | def _allMembers(imembers as IList<of IBoxMember>, members as IList<of IBoxCodeMember>) |
|---|
| 113 | for imember in .declsInOrder |
|---|
| 114 | if imember inherits IBoxCodeMember |
|---|
| 115 | if not any for m in members get m.matchesSignature(imember) |
|---|
| 116 | imembers.add(imember) |
|---|
| 117 | members.add(imember) |
|---|
| 118 | else |
|---|
| 119 | imembers.add(imember) |
|---|
| 120 | for box in .allBaseTypes |
|---|
| 121 | box._allMembers(imembers, members) |
|---|
| 122 | |
|---|
| 123 | def _allExtensionMembers(imembers as IList<of IBoxMember>, members as IList<of IBoxCodeMember>) |
|---|
| 124 | if .compiler and .compiler.nameSpaceStack.count |
|---|
| 125 | .prepIfNeeded |
|---|
| 126 | for ns in .compiler.nameSpaceStack |
|---|
| 127 | _allExtensionMembers(ns, imembers, members) |
|---|
| 128 | for box in .allBaseTypes |
|---|
| 129 | box._allExtensionMembers(imembers, members) |
|---|
| 130 | for ud in .compiler.nameSpaceStack.peek.useDirectives |
|---|
| 131 | _allExtensionMembers(ud.boundNameSpace, imembers, members) |
|---|
| 132 | |
|---|
| 133 | def _allExtensionMembers(ns as NameSpace, imembers as IList<of IBoxMember>, members as IList<of IBoxCodeMember>) |
|---|
| 134 | for decl in ns.declsInOrder |
|---|
| 135 | if decl inherits Extension |
|---|
| 136 | ext = decl |
|---|
| 137 | ext.prepIfNeeded |
|---|
| 138 | if ext.extendedBox == this |
|---|
| 139 | for imember in ext.declsInOrder |
|---|
| 140 | if imember inherits IBoxCodeMember |
|---|
| 141 | if not any for m in members get m.matchesSignature(imember) |
|---|
| 142 | imembers.add(imember) |
|---|
| 143 | members.add(imember) |
|---|
| 144 | else |
|---|
| 145 | imembers.add(imember) |
|---|
| 146 | else if .isGeneric and ext.isGeneric |
|---|
| 147 | # see Extension.extensionMemberFor |
|---|
| 148 | cto = .constructedTypeOf(ext.extendedBox.genericDef to !) |
|---|
| 149 | if cto and .isDescendantOf(cto to !) |
|---|
| 150 | for imember in ext.constructedTypeFor(cto.genericParams).declsInOrder |
|---|
| 151 | if imember inherits IBoxCodeMember |
|---|
| 152 | if not any for m in members get m.matchesSignature(imember) |
|---|
| 153 | imembers.add(imember) |
|---|
| 154 | members.add(imember) |
|---|
| 155 | else |
|---|
| 156 | imembers.add(imember) |
|---|
| 157 | |
|---|
| 158 | get baseClass from var |
|---|
| 159 | |
|---|
| 160 | get baseInterfaces from var |
|---|
| 161 | |
|---|
| 162 | get baseInterfaceProxies from var |
|---|
| 163 | |
|---|
| 164 | get canDeclNamesDifferOnlyByCase as bool is override |
|---|
| 165 | return .nativeType is not nil |
|---|
| 166 | |
|---|
| 167 | get canHaveDetailedStackTrace as bool |
|---|
| 168 | """ |
|---|
| 169 | Normally returns true, but will return false for some key run-time support classes that help *implement* the DST. |
|---|
| 170 | Otherwise, those classes could easily cause infinite recursion / stack overflow. |
|---|
| 171 | Examples include CobraFrame and SourceSite. |
|---|
| 172 | |
|---|
| 173 | Note that returning true does not mean that the -dst option is turned on. |
|---|
| 174 | Returning true only means that this box *can* have code instrumentation for DST. |
|---|
| 175 | """ |
|---|
| 176 | if .name in @['CobraFrame', 'SourceSite'] |
|---|
| 177 | return false # otherwise, stack overflow |
|---|
| 178 | for attribute in .attributes |
|---|
| 179 | if attribute.name == 'DetailedStackTraceAttribute' |
|---|
| 180 | return false |
|---|
| 181 | # probably don't need the following, because this method is only invoked against source code |
|---|
| 182 | if .nativeType |
|---|
| 183 | for attrib in .nativeType.customAttributes |
|---|
| 184 | if attrib inherits DetailedStackTraceAttribute |
|---|
| 185 | if not attrib.flag |
|---|
| 186 | trace attrib, this |
|---|
| 187 | return false |
|---|
| 188 | if .baseClass |
|---|
| 189 | return .baseClass.canHaveDetailedStackTrace |
|---|
| 190 | else |
|---|
| 191 | return true |
|---|
| 192 | |
|---|
| 193 | get canHaveStatements as bool |
|---|
| 194 | """ |
|---|
| 195 | Returns true if the members of the box can contain statements. |
|---|
| 196 | Returns true by default. |
|---|
| 197 | Interfaces return false (in contrast to classes, structs, mixins and extensions). |
|---|
| 198 | """ |
|---|
| 199 | return true |
|---|
| 200 | |
|---|
| 201 | get constructedTypes as IDictionary<of String, Box> |
|---|
| 202 | """ |
|---|
| 203 | The return value is a shallow copy to prevent outside modification of a generic's constructedTypes cache. |
|---|
| 204 | This property exists primarily for debugging/display. |
|---|
| 205 | """ |
|---|
| 206 | return if(_constructedTypes, Dictionary<of String, Box>(_constructedTypes), Dictionary<of String, Box>()) |
|---|
| 207 | |
|---|
| 208 | get defaultAccessLevel as String is override |
|---|
| 209 | return 'public' |
|---|
| 210 | |
|---|
| 211 | get idToken from var as IToken |
|---|
| 212 | |
|---|
| 213 | get isFromBinaryLibrary as bool |
|---|
| 214 | """ |
|---|
| 215 | Returns true if this box was read from a binary library such as a .NET assembly (.dll, .exe) |
|---|
| 216 | or Java binary (.class, .jar) as opposed to be source based. This is independent of |
|---|
| 217 | language. If the binary was originally written in Cobra, this still returns true. |
|---|
| 218 | """ |
|---|
| 219 | ensure |
|---|
| 220 | .isSystemObjectClass implies result |
|---|
| 221 | result implies .nativeType or (.genericDef and .genericDef.nativeType) |
|---|
| 222 | not result implies .nativeType is nil |
|---|
| 223 | body |
|---|
| 224 | return _nativeType or (_genericDef and _genericDef._nativeType) |
|---|
| 225 | |
|---|
| 226 | get isShared as bool is override |
|---|
| 227 | # When a box is declared inside another box (for example, nested classes), you can say: A.B |
|---|
| 228 | # DotExpr needs to know this, hence return true for .isShared |
|---|
| 229 | return true |
|---|
| 230 | |
|---|
| 231 | get invariants from var |
|---|
| 232 | has Subnodes |
|---|
| 233 | |
|---|
| 234 | get hasInvariants as bool |
|---|
| 235 | """ |
|---|
| 236 | Returns true if the box has any invariant conditions whether directly or through inheritance. |
|---|
| 237 | """ |
|---|
| 238 | if _invariants.count |
|---|
| 239 | return true |
|---|
| 240 | if _baseClass |
|---|
| 241 | return _baseClass.hasInvariants |
|---|
| 242 | else |
|---|
| 243 | return false |
|---|
| 244 | |
|---|
| 245 | # TODO: cache |
|---|
| 246 | get isSystemObjectClass as bool is override |
|---|
| 247 | #return _baseClass is nil and .name == 'Object' and .parentNameSpace and .parentNameSpace.fullName == 'System' |
|---|
| 248 | return _nativeType and _nativeType.isSystemObjectClass |
|---|
| 249 | |
|---|
| 250 | get isSystemTypeClass as bool is override |
|---|
| 251 | #return .name == 'Type' and .parentNameSpace and .parentNameSpace.fullName == 'System' |
|---|
| 252 | return _nativeType and _nativeType.isSystemTypeClass |
|---|
| 253 | |
|---|
| 254 | pro membersToUnNil from var |
|---|
| 255 | |
|---|
| 256 | get nativeType from var |
|---|
| 257 | |
|---|
| 258 | get needScanNativeType from var |
|---|
| 259 | |
|---|
| 260 | get nestedBoxes as IEnumerable<of Box> |
|---|
| 261 | for decl in _declsInOrder |
|---|
| 262 | if decl inherits Box |
|---|
| 263 | yield decl |
|---|
| 264 | |
|---|
| 265 | pro parentNameSpace as NameSpace? |
|---|
| 266 | get |
|---|
| 267 | return base.parentNameSpace |
|---|
| 268 | set |
|---|
| 269 | # a box needs to be tied to its local namespace, not the unified one |
|---|
| 270 | assert (value and .token.text <> '(empty)') implies not value.isUnified |
|---|
| 271 | base.parentNameSpace = value |
|---|
| 272 | |
|---|
| 273 | get overloads from var |
|---|
| 274 | |
|---|
| 275 | get nameWithGenericParams as String |
|---|
| 276 | if _genericParams.count |
|---|
| 277 | name = StringBuilder(.rootName+'<of ') |
|---|
| 278 | sep = '' |
|---|
| 279 | for gp in _genericParams |
|---|
| 280 | name.append(sep) |
|---|
| 281 | name.append(gp.name) |
|---|
| 282 | sep = ', ' |
|---|
| 283 | name.append('>') |
|---|
| 284 | return name.toString |
|---|
| 285 | else |
|---|
| 286 | return .name |
|---|
| 287 | |
|---|
| 288 | get rootName as String |
|---|
| 289 | ensure |
|---|
| 290 | '<' not in result |
|---|
| 291 | .name.startsWith(result) |
|---|
| 292 | body |
|---|
| 293 | name = .name |
|---|
| 294 | i = name.indexOf('<') |
|---|
| 295 | if i <> -1 # List<of>, Dictionary<of,> |
|---|
| 296 | name = name[0:i] |
|---|
| 297 | return name |
|---|
| 298 | |
|---|
| 299 | get qualifiedRootName as String |
|---|
| 300 | require |
|---|
| 301 | .parentNameSpace |
|---|
| 302 | ensure |
|---|
| 303 | not result.startsWith('.') |
|---|
| 304 | not result.endsWith('.') |
|---|
| 305 | not .parentNameSpace.isRoot implies '.' in result |
|---|
| 306 | body |
|---|
| 307 | return _qualifiedPrefix + .rootName |
|---|
| 308 | |
|---|
| 309 | get qualifiedName as String |
|---|
| 310 | return _qualifiedPrefix + .name |
|---|
| 311 | |
|---|
| 312 | get _qualifiedPrefix as String |
|---|
| 313 | ensure |
|---|
| 314 | result.length implies result.endsWith('.') |
|---|
| 315 | ' ' not in result |
|---|
| 316 | body |
|---|
| 317 | nameSpaces = List<of NameSpace>() |
|---|
| 318 | ns = .parentNameSpace |
|---|
| 319 | while ns and not ns.isRoot |
|---|
| 320 | nameSpaces.add(ns to !) |
|---|
| 321 | assert ns is not ns.superNameSpace |
|---|
| 322 | ns = ns.superNameSpace |
|---|
| 323 | nameSpaces.reverse |
|---|
| 324 | prefix = (for ns in nameSpaces get ns.name).join('.') |
|---|
| 325 | if prefix.length |
|---|
| 326 | prefix += '.' |
|---|
| 327 | return prefix |
|---|
| 328 | |
|---|
| 329 | get superType as IType? is override |
|---|
| 330 | or require true |
|---|
| 331 | if not .didBindInh, .bindInh |
|---|
| 332 | assert .didBindInh |
|---|
| 333 | return _baseClass |
|---|
| 334 | |
|---|
| 335 | pro testMethods from var |
|---|
| 336 | |
|---|
| 337 | get isExtern as bool |
|---|
| 338 | return 'extern' in _isNames |
|---|
| 339 | |
|---|
| 340 | def constructedTypeOf(box as Box) as Box? |
|---|
| 341 | require |
|---|
| 342 | .didBindInh |
|---|
| 343 | box.isGenericDef |
|---|
| 344 | ensure |
|---|
| 345 | result implies result is this or result in .allBaseTypes |
|---|
| 346 | body |
|---|
| 347 | if .genericDef is box, return this |
|---|
| 348 | for bt in .allBaseTypes, if bt.genericDef is box, return bt |
|---|
| 349 | return nil |
|---|
| 350 | |
|---|
| 351 | def isDescendantOfInterface(inter as Interface) as bool |
|---|
| 352 | require .didBindInh or .nativeType |
|---|
| 353 | _prepLibraryBox |
|---|
| 354 | if this == inter, return true |
|---|
| 355 | if _baseInterfaces.count == 0 and _baseInterfaceProxies.count, .bindInh |
|---|
| 356 | if .compiler, inter.bindInh |
|---|
| 357 | assert .serialNum <> inter.serialNum |
|---|
| 358 | assert _baseInterfaceProxies.count == 0 or _baseInterfaces.count == _baseInterfaceProxies.count |
|---|
| 359 | for bit in _baseInterfaces |
|---|
| 360 | if bit.isDescendantOfInterface(inter) |
|---|
| 361 | return true |
|---|
| 362 | return false |
|---|
| 363 | |
|---|
| 364 | def allMembersForName(name as String) as Set<of IBoxMember> |
|---|
| 365 | """ |
|---|
| 366 | Returns a set of all members with a given name, including inherited members, |
|---|
| 367 | with no duplicates and no guaranteed order. |
|---|
| 368 | """ |
|---|
| 369 | return Set<of IBoxMember>(_allMembersForName(name)) |
|---|
| 370 | |
|---|
| 371 | def _allMembersForName(name as String) as IBoxMember* |
|---|
| 372 | decl = .declForName(name) |
|---|
| 373 | if decl, yield decl |
|---|
| 374 | if .baseClass |
|---|
| 375 | for m in .baseClass._allMembersForName(name) |
|---|
| 376 | yield m |
|---|
| 377 | for inter in _baseInterfaces |
|---|
| 378 | for m in inter._allMembersForName(name) |
|---|
| 379 | yield m |
|---|
| 380 | |
|---|
| 381 | def cobraSourceSignature as String |
|---|
| 382 | return .idString |
|---|
| 383 | |
|---|
| 384 | def interfaceMemberForName(name as String) as IBoxMember? |
|---|
| 385 | m = .declForName(name) |
|---|
| 386 | if m, return m |
|---|
| 387 | for inter in _baseInterfaces |
|---|
| 388 | m = inter.interfaceMemberForName(name) |
|---|
| 389 | if m, break |
|---|
| 390 | return m |
|---|
| 391 | |
|---|
| 392 | def makeNextPrivateSerialNumber as int |
|---|
| 393 | n = _nextPrivateSerialNumber |
|---|
| 394 | _nextPrivateSerialNumber += 1 |
|---|
| 395 | return n |
|---|
| 396 | |
|---|
| 397 | def mergedIntoPartialBox(newBox as Box) |
|---|
| 398 | require |
|---|
| 399 | newBox is not .parentBox |
|---|
| 400 | newBox.name == .parentBox.name |
|---|
| 401 | body |
|---|
| 402 | _parentBox = newBox |
|---|
| 403 | |
|---|
| 404 | get canAccessMemberForName as bool is override |
|---|
| 405 | return .didBindInh or (.nativeType and (.compiler.isBindingInt or .compiler.isBindingImp)) |
|---|
| 406 | |
|---|
| 407 | def extensionMemberFor(box as Box, name as String) as IMember? |
|---|
| 408 | # in the future, in support of C# 3.0, it will be necessary to implement this |
|---|
| 409 | # to find the static extension methods like "static void Foo(this String s, ...)", |
|---|
| 410 | # or for Extensions to be instantiated when DLLs are scanned |
|---|
| 411 | return nil |
|---|
| 412 | |
|---|
| 413 | def mangleName(name as String) as String |
|---|
| 414 | return name |
|---|
| 415 | |
|---|
| 416 | def memberForName(name as String) as IMember? is override |
|---|
| 417 | if .compiler and .compiler.nodeStack.count and (.compiler.nodeStack.peek to Node).isBindingImp |
|---|
| 418 | return __memberForNameIncludingExtensions(name) |
|---|
| 419 | else |
|---|
| 420 | return __memberForName(name) |
|---|
| 421 | |
|---|
| 422 | def __memberForName(name as String) as IMember? |
|---|
| 423 | .prepIfNeeded |
|---|
| 424 | return base.memberForName(name) |
|---|
| 425 | |
|---|
| 426 | def __memberForNameIncludingExtensions(name as String) as IMember? |
|---|
| 427 | m = __memberForName(name) |
|---|
| 428 | if m is nil and .compiler |
|---|
| 429 | # look for an extension member, but it has to be accessible according to namespaces |
|---|
| 430 | if .compiler.nameSpaceStack.count |
|---|
| 431 | # don't need to go through the whole namespace stack because the namespace will check its parent |
|---|
| 432 | m = .compiler.curNameSpace.extensionMemberFor(this, name) |
|---|
| 433 | return m |
|---|
| 434 | |
|---|
| 435 | def suggestionsForBadMemberName(name as String) as List<of String> |
|---|
| 436 | suggs = base.suggestionsForBadMemberName(name) |
|---|
| 437 | if _baseClass |
|---|
| 438 | suggs.addRange(_baseClass.suggestionsForBadMemberName(name)) |
|---|
| 439 | for bi in _baseInterfaces |
|---|
| 440 | suggs.addRange(bi.suggestionsForBadMemberName(name)) |
|---|
| 441 | |
|---|
| 442 | # eliminate duplicates |
|---|
| 443 | suggs = List<of String>(Set<of String>(suggs)) |
|---|
| 444 | |
|---|
| 445 | # sort |
|---|
| 446 | suggs.sort(ref _compareMemberNames) |
|---|
| 447 | |
|---|
| 448 | # okay to sort by alpha, but if a name differs only by case, put it up front |
|---|
| 449 | lowerName = name.toLower |
|---|
| 450 | for i in suggs.count |
|---|
| 451 | if suggs[i].toLower == lowerName |
|---|
| 452 | sugg = suggs[i] |
|---|
| 453 | suggs.removeAt(i) |
|---|
| 454 | suggs.insert(0, sugg) |
|---|
| 455 | break |
|---|
| 456 | return suggs |
|---|
| 457 | |
|---|
| 458 | def _compareMemberNames(a as String, b as String) as int |
|---|
| 459 | ensure result in {-1, 0, +1} |
|---|
| 460 | # put '_foo' after 'foo' |
|---|
| 461 | if a.startsWith('_') and not b.startsWith('_') |
|---|
| 462 | diff = a[1:].compareTo(b) |
|---|
| 463 | return if(diff == 0, 1, diff) |
|---|
| 464 | if not a.startsWith('_') and b.startsWith('_') |
|---|
| 465 | diff = a.compareTo(b[1:]) |
|---|
| 466 | return if(diff == 0, -1, diff) |
|---|
| 467 | return a.compareTo(b) |
|---|
| 468 | |
|---|
| 469 | def prepIfNeeded |
|---|
| 470 | if _nativeType, _prepLibraryBox |
|---|
| 471 | else, .completeMemberConstructionIfNeeded |
|---|
| 472 | |
|---|
| 473 | def registerOverload(ol as MemberOverload) |
|---|
| 474 | require |
|---|
| 475 | ol.name.length |
|---|
| 476 | ol not in _overloads |
|---|
| 477 | body |
|---|
| 478 | _overloads.add(ol) |
|---|
| 479 | _declsByName[ol.name] = ol |
|---|
| 480 | _declsByNameCI[ol.name.toLower] = ol |
|---|
| 481 | |
|---|
| 482 | def addDeclFromOverload(decl as IBoxMember, ol as MemberOverload) |
|---|
| 483 | require |
|---|
| 484 | ol in .overloads |
|---|
| 485 | decl.name == ol.name |
|---|
| 486 | body |
|---|
| 487 | _declsInOrder.add(decl) |
|---|
| 488 | |
|---|
| 489 | def paramForName(name as String) as IType? |
|---|
| 490 | # linear search is okay here since generic arg count is usually 0, 1 or 2 |
|---|
| 491 | for param in _genericParams, if name == param.name, return param |
|---|
| 492 | return nil |
|---|
| 493 | |
|---|
| 494 | def symbolForName(name as String, haveThis as bool) as IMember? |
|---|
| 495 | return .symbolForName(name, haveThis, true) |
|---|
| 496 | |
|---|
| 497 | def symbolForName(name as String, haveThis as bool, firstCall as bool) as IMember? |
|---|
| 498 | """ |
|---|
| 499 | Unlike the inherited .declForName, this method follows the |
|---|
| 500 | inheritance chain and provides options for haveThis. |
|---|
| 501 | |
|---|
| 502 | TODO: |
|---|
| 503 | This method should be protected, but then this expression in the override in Extension: |
|---|
| 504 | .extendedBox._symbolForName(name, haveThis, firstCall) |
|---|
| 505 | Gives this error message in C#: |
|---|
| 506 | Cannot access protected member "Box._symbolForName(string, bool, bool)" via a qualifier of type "Box"; the qualifier must be of type "Extension" (or derived from it) |
|---|
| 507 | Is this a limitation of C# or CLR? Do Java, C++ and D have the same restruction? |
|---|
| 508 | """ |
|---|
| 509 | if firstCall and name == _name |
|---|
| 510 | return this |
|---|
| 511 | p = .paramForName(name) |
|---|
| 512 | if p |
|---|
| 513 | if haveThis |
|---|
| 514 | .throwError('Cannot refer to a generic parameter ("[name]") through `this`.') |
|---|
| 515 | else |
|---|
| 516 | return p |
|---|
| 517 | x = .declForName(name) to IMember? |
|---|
| 518 | if x is nil and _baseClass |
|---|
| 519 | # try base class to look for nested types |
|---|
| 520 | x = _baseClass.symbolForName(name, haveThis, false) |
|---|
| 521 | if x is nil |
|---|
| 522 | x = .interfaceMemberForName(name) # TODO: can this be guarded by haveThis? can interfaces have enum decls and sigs? |
|---|
| 523 | if x and not haveThis |
|---|
| 524 | if x.requiresThis, x = nil |
|---|
| 525 | if x is nil and firstCall |
|---|
| 526 | # TODO: can this be guarded by haveThis |
|---|
| 527 | # try parent box or namespace because they are in lexical scope |
|---|
| 528 | nameSpace = .parentNameSpace |
|---|
| 529 | if nameSpace is nil |
|---|
| 530 | # happens for nested boxes which currently means sig/delegate inside a class |
|---|
| 531 | # when classes can really be nested, or generic sigs are supported, we'll need some more work here |
|---|
| 532 | if .parentBox |
|---|
| 533 | x = .parentBox.symbolForName(name, haveThis, firstCall) |
|---|
| 534 | else |
|---|
| 535 | if not .name.startsWith('ArrayType_') # TODO: axe this guard when ArrayType.memberForName's TODO to read the Array library type is done |
|---|
| 536 | if .didBindInt |
|---|
| 537 | assert nameSpace |
|---|
| 538 | assert not nameSpace.isUnified |
|---|
| 539 | x = nameSpace.symbolForName(name) |
|---|
| 540 | return x |
|---|
| 541 | |
|---|
| 542 | ## INamedNode |
|---|
| 543 | |
|---|
| 544 | get typeForIdentifier as IType is override |
|---|
| 545 | assert .compiler |
|---|
| 546 | return .compiler.typeType |
|---|
| 547 | |
|---|
| 548 | get typeForReceiver as IType is override |
|---|
| 549 | return this |
|---|
| 550 | |
|---|
| 551 | ## IType |
|---|
| 552 | |
|---|
| 553 | get innerType as IType? is override |
|---|
| 554 | .prepIfNeeded |
|---|
| 555 | if this is .compiler.stringType # TODO: hacky. solution is to look at the specific type of .current property of enumerator. make a test case that shows that |
|---|
| 556 | return .compiler.charType |
|---|
| 557 | # TODO: can a for loop go through an IEnumerator<of>? |
|---|
| 558 | # if .isConstructed and .genericDef is .compiler.enumeratorOfType |
|---|
| 559 | # return .genericParams[0] |
|---|
| 560 | getEnum as IMember? |
|---|
| 561 | if .declForName('getEnumerator') is nil |
|---|
| 562 | # Comes up for IList<of T> which has multiple 'getEnumerator' methods in ancestor interfaces |
|---|
| 563 | for member in .allMembersForName('getEnumerator') |
|---|
| 564 | if member inherits Method and member.parentBox.isGeneric |
|---|
| 565 | getEnum = member |
|---|
| 566 | break |
|---|
| 567 | if getEnum is nil |
|---|
| 568 | getEnum = .symbolForName('getEnumerator', true) |
|---|
| 569 | if getEnum |
|---|
| 570 | assert getEnum.didBindInt |
|---|
| 571 | # can have two getEnumerators -- one generic and the other not. favor the generic one |
|---|
| 572 | if getEnum inherits MemberOverload |
|---|
| 573 | for member in getEnum.members |
|---|
| 574 | if member inherits Method |
|---|
| 575 | if member.resultType <> .compiler.objectType |
|---|
| 576 | # implementing IEnumerable<of T> which requires two `getEnumerator` members |
|---|
| 577 | getEnum = member |
|---|
| 578 | break |
|---|
| 579 | rt = getEnum.resultType |
|---|
| 580 | if rt.isDynamicOrPassThrough |
|---|
| 581 | return rt |
|---|
| 582 | rt = rt.nonNil # nilable is not a concern; unwrap it |
|---|
| 583 | if rt inherits Box and (rt to Box).isGeneric |
|---|
| 584 | # don't take the first argument of the result type -- that won't work for a nested type in a generic class, like ValueCollection, which gets the generic params of its parents |
|---|
| 585 | rt = rt.memberForName('current').resultType |
|---|
| 586 | return rt |
|---|
| 587 | else |
|---|
| 588 | if rt.isDescendantOf(.compiler.dictEnumeratorType) |
|---|
| 589 | return rt.memberForName('entry').resultType |
|---|
| 590 | if rt.isDescendantOf(.compiler.enumeratorType) |
|---|
| 591 | rt = rt.memberForName('current').resultType |
|---|
| 592 | if rt.nonNil.isSystemObjectClass |
|---|
| 593 | # can we do better with indexer returnType? (e.g. MatchCollection) |
|---|
| 594 | indexer = .symbolForName(r'[]', true) |
|---|
| 595 | if indexer, rt = indexer.resultType |
|---|
| 596 | return rt |
|---|
| 597 | else |
|---|
| 598 | throw FallThroughException({'rt': rt, 'this': this, 'getEnum': getEnum}) |
|---|
| 599 | return nil |
|---|
| 600 | |
|---|
| 601 | def isEquatableTo(t as IType) as bool |
|---|
| 602 | r = base.isEquatableTo(t) |
|---|
| 603 | if not r and t inherits CharType and this is .compiler.stringType # TODO: hacky? could this be determined by looking for a static == operator overload? |
|---|
| 604 | r = true |
|---|
| 605 | if not r and ('dynamic' in .name or 'dynamic' in t.name) # TODO: hacky |
|---|
| 606 | r = true |
|---|
| 607 | if not r and t inherits ArrayType and (t to ArrayType).isEquatableTo(this) # TODO: hacky |
|---|
| 608 | r = true |
|---|
| 609 | return r |
|---|
| 610 | |
|---|
| 611 | def isComparableTo(t as IType) as bool |
|---|
| 612 | r = base.isComparableTo(t) |
|---|
| 613 | if not r and t inherits CharType and this is .compiler.stringType # TODO: hacky? could this be determined by looking for a static == operator overload? |
|---|
| 614 | r = true |
|---|
| 615 | if not r and ('dynamic' in .name or 'dynamic' in t.name) # TODO: hacky |
|---|
| 616 | r = true |
|---|
| 617 | return r |
|---|
| 618 | |
|---|
| 619 | ## Binding |
|---|
| 620 | def _scanNativeType |
|---|
| 621 | #print '_scanNativeType ', .name |
|---|
| 622 | assert .compiler |
|---|
| 623 | .backEnd.scanNativeType(this) # Convert library (native) info to Cobra data structures |
|---|
| 624 | |
|---|
| 625 | def _stackPush |
|---|
| 626 | base._stackPush |
|---|
| 627 | if .compiler, .compiler.boxStack.push(this) |
|---|
| 628 | |
|---|
| 629 | def _stackPop |
|---|
| 630 | base._stackPop |
|---|
| 631 | if .compiler, .compiler.boxStack.pop |
|---|
| 632 | |
|---|
| 633 | def bindInh |
|---|
| 634 | base.bindInh |
|---|
| 635 | # nested types |
|---|
| 636 | if .didBindInh and not .isBindingInh |
|---|
| 637 | for decl in .declsInOrder, if decl implements IType, decl.bindInh |
|---|
| 638 | |
|---|
| 639 | def _bindInh |
|---|
| 640 | base._bindInh |
|---|
| 641 | if _needScanNativeType, _scanNativeType |
|---|
| 642 | _checkModifiers |
|---|
| 643 | _bindBase |
|---|
| 644 | # structs, classes and interfaces can all have 0 or more interfaces they inherit/implement |
|---|
| 645 | if _baseInterfaceProxies.count <> _baseInterfaces.count # otherwise, already done |
|---|
| 646 | assert _baseInterfaces.count == 0 |
|---|
| 647 | for interfaceProxy in _baseInterfaceProxies |
|---|
| 648 | try |
|---|
| 649 | baseWhat = interfaceProxy.realType |
|---|
| 650 | if baseWhat inherits Interface |
|---|
| 651 | _baseInterfaces.add(baseWhat) |
|---|
| 652 | else |
|---|
| 653 | _badInterfaceError(baseWhat) |
|---|
| 654 | catch ne as NodeException |
|---|
| 655 | hadBaseInterfaceError = ne to ? |
|---|
| 656 | .compiler.recordError(ne) |
|---|
| 657 | _checkForInheritanceCycles(this, Stack<of Box>()) |
|---|
| 658 | if _baseClass, _baseClass.bindInh |
|---|
| 659 | for interf in _baseInterfaces, interf.bindInh |
|---|
| 660 | |
|---|
| 661 | # .bindInh on the .nestedBoxes causes problems. ticket:127 |
|---|
| 662 | # for box in .nestedBoxes, box.bindInh |
|---|
| 663 | |
|---|
| 664 | # trace this, hadBaseInterfaceError, .baseInterfaceProxies, .baseInterfaces |
|---|
| 665 | assert hadBaseInterfaceError or .baseInterfaceProxies.count == 0 or .baseInterfaceProxies.count == .baseInterfaces.count, [.baseInterfaceProxies.count, .baseInterfaces.count] |
|---|
| 666 | |
|---|
| 667 | def _checkModifiers |
|---|
| 668 | if 'readonly' in .isNames |
|---|
| 669 | .recordError('The keyword "readonly" does not apply to [Utils.pluralize(.englishName)].') |
|---|
| 670 | |
|---|
| 671 | def _checkForInheritanceCycles(originalBox as Box, bases as Stack<of Box>) |
|---|
| 672 | if this in bases |
|---|
| 673 | names = for aBase in List<of Box>(Stack<of Box>(bases))[1:] get aBase.name |
|---|
| 674 | .throwError('Cyclical inheritance for "[.name]" with ancestor types [names.join(", ")] and back to [.name].') |
|---|
| 675 | else |
|---|
| 676 | bases.push(this) |
|---|
| 677 | if .baseClass, .baseClass._checkForInheritanceCycles(originalBox, bases) |
|---|
| 678 | for bi in .baseInterfaces, bi._checkForInheritanceCycles(originalBox, bases) |
|---|
| 679 | bases.pop |
|---|
| 680 | |
|---|
| 681 | def bindInt as INode |
|---|
| 682 | if not .didBindInt and not .isBindingInt |
|---|
| 683 | # because DLL boxes get bindInh and bindInt on demand, check this: |
|---|
| 684 | if _genericDef |
|---|
| 685 | assert _genericDef is not this |
|---|
| 686 | if not _genericDef.didBindInt and not _genericDef.isBindingInt |
|---|
| 687 | _genericDef.bindInt |
|---|
| 688 | assert _genericDef.didBindInt or _genericDef.isBindingInt |
|---|
| 689 | if .nativeType |
|---|
| 690 | _prepLibraryBox |
|---|
| 691 | else if not .didBindInh |
|---|
| 692 | .bindInh |
|---|
| 693 | if _genericDef |
|---|
| 694 | assert _genericDef is not this |
|---|
| 695 | assert _genericDef.didBindInt or _genericDef.isBindingInt |
|---|
| 696 | return base.bindInt |
|---|
| 697 | |
|---|
| 698 | def _bindInt |
|---|
| 699 | # Note that .bindInt (not this method, _bindInt) already ensures that if this box is constructed, its generic def binds int *first*. |
|---|
| 700 | # Therefore, everthing below has already happened for a constructed box's generic def. |
|---|
| 701 | base._bindInt |
|---|
| 702 | if .isSystemObjectClass |
|---|
| 703 | assert .compiler |
|---|
| 704 | .backEnd.prepSystemObjectClass(this) # add any improvements to root Object |
|---|
| 705 | errorCount = .compiler.errors.count |
|---|
| 706 | if _needScanNativeType, _scanNativeType |
|---|
| 707 | if _baseClass |
|---|
| 708 | _baseClass.bindInt |
|---|
| 709 | for interf in _baseInterfaces |
|---|
| 710 | interf.bindInt |
|---|
| 711 | for param in _genericParams |
|---|
| 712 | param.bindInt |
|---|
| 713 | if not .isConstructed # because constructed boxes are already taken care of by way of their generic type def |
|---|
| 714 | .unNilReturnTypes(this) |
|---|
| 715 | for attrib in _attribs |
|---|
| 716 | try |
|---|
| 717 | attrib.bindInt |
|---|
| 718 | catch ne as NodeException |
|---|
| 719 | .compiler.recordError(ne) |
|---|
| 720 | for invari in _invariants |
|---|
| 721 | invari.bindInt |
|---|
| 722 | _makeInitializers |
|---|
| 723 | hasError = false |
|---|
| 724 | for decl in List<of IBoxMember>(_declsInOrder) |
|---|
| 725 | assert not decl is this |
|---|
| 726 | .compiler.boxMemberStack.push(decl) |
|---|
| 727 | try |
|---|
| 728 | if decl inherits BoxMember |
|---|
| 729 | if decl.parentBox is not this # TODO: when does this happen |
|---|
| 730 | continue |
|---|
| 731 | decl.bindInt |
|---|
| 732 | catch ne as NodeException |
|---|
| 733 | .compiler.recordError(ne) |
|---|
| 734 | hasError = true |
|---|
| 735 | finally |
|---|
| 736 | .compiler.boxMemberStack.pop |
|---|
| 737 | if not hasError |
|---|
| 738 | _finishOverloads |
|---|
| 739 | for tm in _testMethods |
|---|
| 740 | .compiler.boxMemberStack.push(tm) |
|---|
| 741 | try, tm.bindInt |
|---|
| 742 | finally, .compiler.boxMemberStack.pop |
|---|
| 743 | if _constructedTypes |
|---|
| 744 | if .compiler.errors.count <= errorCount # completing construction on constructed types leads to chaos if this generic def had errors during bind interface |
|---|
| 745 | for ct in _constructedTypes.values.toList |
|---|
| 746 | assert ct is not this |
|---|
| 747 | ct.completeMemberConstructionIfNeeded |
|---|
| 748 | ct.bindInt |
|---|
| 749 | |
|---|
| 750 | def _bindBase |
|---|
| 751 | # invoked by _bindInt |
|---|
| 752 | _baseClass = .compiler.objectClass |
|---|
| 753 | |
|---|
| 754 | def _badInterfaceError(type as IType) |
|---|
| 755 | .throwError('Cannot inherit "[type.name]" which is a [type.englishName].') |
|---|
| 756 | |
|---|
| 757 | def _makeInitializers |
|---|
| 758 | pass |
|---|
| 759 | |
|---|
| 760 | def _finishOverloads |
|---|
| 761 | # this method is broken out so Class can override and deal with inheritance and overloads |
|---|
| 762 | for ol in _overloads |
|---|
| 763 | try |
|---|
| 764 | ol.bindInt |
|---|
| 765 | catch ne as NodeException |
|---|
| 766 | .compiler.recordError(ne) |
|---|
| 767 | |
|---|
| 768 | def _computeMatchingBaseMembers |
|---|
| 769 | base._computeMatchingBaseMembers |
|---|
| 770 | for decl in .declsInOrder |
|---|
| 771 | decl.computeMatchingBaseMembers |
|---|
| 772 | |
|---|
| 773 | def _bindImp |
|---|
| 774 | base._bindImp |
|---|
| 775 | assert .didBindInt |
|---|
| 776 | for attrib in _attribs |
|---|
| 777 | try |
|---|
| 778 | attrib.bindImp |
|---|
| 779 | catch ne as NodeException |
|---|
| 780 | .compiler.recordError(ne) |
|---|
| 781 | for i in _invariants.count |
|---|
| 782 | invari = _invariants[i].bindImp |
|---|
| 783 | if invari.type is not .compiler.boolType |
|---|
| 784 | _invariants[i] = TruthExpr(invari).bindAll to Expr |
|---|
| 785 | # TODO: should be able to remove the following |
|---|
| 786 | for invari in _invariants |
|---|
| 787 | invari.bindImp |
|---|
| 788 | for decl in List<of IBoxMember>(_declsInOrder) |
|---|
| 789 | assert not decl is this |
|---|
| 790 | .compiler.boxMemberStack.push(decl) |
|---|
| 791 | try |
|---|
| 792 | if decl inherits BoxMember |
|---|
| 793 | if decl.parentBox is not this |
|---|
| 794 | continue |
|---|
| 795 | decl.bindImp |
|---|
| 796 | catch ne as NodeException |
|---|
| 797 | .compiler.recordError(ne) |
|---|
| 798 | finally |
|---|
| 799 | .compiler.boxMemberStack.pop |
|---|
| 800 | for ol in _overloads |
|---|
| 801 | try |
|---|
| 802 | ol.bindImp |
|---|
| 803 | catch ne as NodeException |
|---|
| 804 | .compiler.recordError(ne) |
|---|
| 805 | for tm in _testMethods |
|---|
| 806 | .compiler.boxMemberStack.push(tm) |
|---|
| 807 | try, tm.bindImp |
|---|
| 808 | finally, .compiler.boxMemberStack.pop |
|---|
| 809 | |
|---|
| 810 | def _prepLibraryBox |
|---|
| 811 | ensure .didBindInh |
|---|
| 812 | if _nativeType and not _didPrep |
|---|
| 813 | __prepLibraryBox |
|---|
| 814 | |
|---|
| 815 | var _didPrep as bool |
|---|
| 816 | |
|---|
| 817 | def __prepLibraryBox |
|---|
| 818 | """ |
|---|
| 819 | DLL types get bindInh & bindInt only on demand. (Otherwise reading system DLLs slows things down.) |
|---|
| 820 | """ |
|---|
| 821 | require .nativeType |
|---|
| 822 | ensure .didBindInh |
|---|
| 823 | if _didPrep, return |
|---|
| 824 | _didPrep = true |
|---|
| 825 | if not .didBindInh |
|---|
| 826 | .bindInh |
|---|
| 827 | assert .didBindInh |
|---|
| 828 | if not .didBindInt and not .compiler.isBindingInh |
|---|
| 829 | .bindInt |
|---|
| 830 | assert .didBindInt |
|---|
| 831 | |
|---|
| 832 | var _didUnNilReturnTypes as bool |
|---|
| 833 | |
|---|
| 834 | get didUnNilReturnTypes as bool |
|---|
| 835 | if .isConstructed |
|---|
| 836 | return .genericDef.didUnNilReturnTypes |
|---|
| 837 | else |
|---|
| 838 | return _didUnNilReturnTypes |
|---|
| 839 | |
|---|
| 840 | def unNilReturnTypes(box as Box) |
|---|
| 841 | if .compiler.isBindingInh |
|---|
| 842 | # because the .membersToUnNil properties won't even be set until the compiler starts .bindInt |
|---|
| 843 | return |
|---|
| 844 | if _didUnNilReturnTypes |
|---|
| 845 | return |
|---|
| 846 | _didUnNilReturnTypes = true |
|---|
| 847 | _unNilReturnTypes(box) |
|---|
| 848 | |
|---|
| 849 | def _unNilReturnTypes(box as Box) |
|---|
| 850 | assert not _needScanNativeType |
|---|
| 851 | if box.membersToUnNil |
|---|
| 852 | for name in box.membersToUnNil.split |
|---|
| 853 | m = .declForName(name) # using .memberForName here is unnecessary and could/would cause an infinite loop |
|---|
| 854 | if m |
|---|
| 855 | m.unNilReturnType |
|---|
| 856 | # follow inheritance to look at ancestors' .membersToUnNil |
|---|
| 857 | if box.baseClass |
|---|
| 858 | _unNilReturnTypes(box.baseClass to !) |
|---|
| 859 | for interf in box.baseInterfaces |
|---|
| 860 | _unNilReturnTypes(interf) |
|---|
| 861 | |
|---|
| 862 | ## Generics |
|---|
| 863 | |
|---|
| 864 | def isAssignableTo(type as IType) as bool |
|---|
| 865 | .prepIfNeeded |
|---|
| 866 | r = base.isAssignableTo(type) |
|---|
| 867 | if not r |
|---|
| 868 | type = type.nonNil |
|---|
| 869 | if type inherits PrimitiveType |
|---|
| 870 | if type.systemAliasType == this |
|---|
| 871 | return true # example: this is Int32 and type is int |
|---|
| 872 | if type inherits Box |
|---|
| 873 | if (.isGeneric and type.isGeneric and .genericDef is type.genericDef) or (.isGenericDef and type.isGeneric and this is type.genericDef) |
|---|
| 874 | # CC?: r = all for i, gp in .genericParams.numbered get gp.isAssignableTo(type.genericParams[i]) |
|---|
| 875 | # CC?: r = for i, gp in .genericParams.numbered get all gp.isAssignableTo(type.genericParams[i]) |
|---|
| 876 | i = 0 |
|---|
| 877 | r = true |
|---|
| 878 | for gp in .genericParams # CC: for i, gp in .genericParams.numbered |
|---|
| 879 | if not gp.isAssignableTo(type.genericParams[i]) |
|---|
| 880 | r = false |
|---|
| 881 | break |
|---|
| 882 | i += 1 |
|---|
| 883 | else if type.isGenericDef and .isGeneric and type is .genericDef |
|---|
| 884 | r = type.isAssignableTo(this) |
|---|
| 885 | if not r |
|---|
| 886 | if type inherits StreamType |
|---|
| 887 | r = .isAssignableTo(type.box to !) |
|---|
| 888 | return r |
|---|
| 889 | |
|---|
| 890 | get isConstructed as bool |
|---|
| 891 | return _genericDef is not nil |
|---|
| 892 | |
|---|
| 893 | def isDirectConstructionOf(box as Box) as bool |
|---|
| 894 | """ |
|---|
| 895 | Returns true if this type was directly constructed from the given box. |
|---|
| 896 | """ |
|---|
| 897 | require |
|---|
| 898 | .didBindInh |
|---|
| 899 | box.isGenericDef |
|---|
| 900 | body |
|---|
| 901 | return .genericDef is box |
|---|
| 902 | |
|---|
| 903 | def isIndirectConstructionOf(box as Box) as bool |
|---|
| 904 | """ |
|---|
| 905 | Returns true if this type or any of its ancestor types |
|---|
| 906 | is a construction of the given generic type def. |
|---|
| 907 | """ |
|---|
| 908 | require |
|---|
| 909 | .didBindInh |
|---|
| 910 | box.isGenericDef |
|---|
| 911 | body |
|---|
| 912 | return .constructedTypeOf(box) is not nil |
|---|
| 913 | |
|---|
| 914 | get isGenericDef as bool |
|---|
| 915 | """ |
|---|
| 916 | Returns true if this type is a definition of a generic type, and |
|---|
| 917 | therefore capable of making subsequent generic types via the |
|---|
| 918 | `constructedTypeFor` method. A generic type will have generic |
|---|
| 919 | parameters which are all GenericParam (as opposed to other types |
|---|
| 920 | such as `int` or a given class). |
|---|
| 921 | """ |
|---|
| 922 | # TODO: make this more efficient, maybe by computing in the initializer |
|---|
| 923 | if _genericDef |
|---|
| 924 | return false |
|---|
| 925 | else if _genericParams.count |
|---|
| 926 | for param in _genericParams |
|---|
| 927 | if not param inherits GenericParam |
|---|
| 928 | return false |
|---|
| 929 | return true |
|---|
| 930 | else |
|---|
| 931 | return false |
|---|
| 932 | |
|---|
| 933 | get isGeneric as bool |
|---|
| 934 | """ |
|---|
| 935 | Returns true if this type is a generic type which includes |
|---|
| 936 | generic type defs and open-or-closed constructed types. Note |
|---|
| 937 | that arrays of generic types and pointers to generic types will |
|---|
| 938 | return false. |
|---|
| 939 | """ |
|---|
| 940 | return _genericParams.count > 0 |
|---|
| 941 | |
|---|
| 942 | get genericParams as List<of IType> |
|---|
| 943 | """ |
|---|
| 944 | Return the list of generic params for this generic type. This |
|---|
| 945 | property requires that .isGenericDef is true. |
|---|
| 946 | """ |
|---|
| 947 | require .isGeneric |
|---|
| 948 | return _genericParams |
|---|
| 949 | |
|---|
| 950 | get genericDef as Box? |
|---|
| 951 | """ |
|---|
| 952 | Returns the generic type definition for a constructed type (or nil if this type is not constructed). |
|---|
| 953 | """ |
|---|
| 954 | return _genericDef |
|---|
| 955 | |
|---|
| 956 | def extendedMethodGenericParams(genericParams as IList<of IType>) as IList<of IType> |
|---|
| 957 | """ |
|---|
| 958 | This is a hook for Extension and Method which have to deal with extensions on generic classes. |
|---|
| 959 | """ |
|---|
| 960 | ensure |
|---|
| 961 | old genericParams == genericParams |
|---|
| 962 | result.count >= genericParams.count |
|---|
| 963 | body |
|---|
| 964 | return genericParams |
|---|
| 965 | |
|---|
| 966 | def constructedTypeFor(typeArgs as List<of IType>) as Box |
|---|
| 967 | require |
|---|
| 968 | .isGenericDef |
|---|
| 969 | .containsGenericParameters |
|---|
| 970 | typeArgs.count == .genericParams.count |
|---|
| 971 | ensure |
|---|
| 972 | result is not this and result.genericDef is this |
|---|
| 973 | result.genericParams == typeArgs |
|---|
| 974 | not result.isGenericDef |
|---|
| 975 | body |
|---|
| 976 | _prepLibraryBox |
|---|
| 977 | |
|---|
| 978 | # the cache of constructed types has to come from the root generic type def or you end up with duplicate |
|---|
| 979 | # constructed types which is not only wasteful, but causes problems with inheritance tests |
|---|
| 980 | if .genericDef, return .genericDef.constructedTypeFor(typeArgs) |
|---|
| 981 | |
|---|
| 982 | if _constructedTypes is nil, _constructedTypes = Dictionary<of String, Box>() |
|---|
| 983 | |
|---|
| 984 | key = TypeUtil.keyForTypeArgs(typeArgs) |
|---|
| 985 | |
|---|
| 986 | if _constructedTypes.containsKey(key), return _constructedTypes[key] |
|---|
| 987 | |
|---|
| 988 | assert not .isBindingInh |
|---|
| 989 | |
|---|
| 990 | if not .didBindInh |
|---|
| 991 | assert not .didBindInt |
|---|
| 992 | .bindInh |
|---|
| 993 | assert not .didBindInt |
|---|
| 994 | if .nativeType |
|---|
| 995 | _prepLibraryBox |
|---|
| 996 | assert not .didBindInt or not .compiler.isBindingInh |
|---|
| 997 | |
|---|
| 998 | assert _baseInterfaceProxies.count == _baseInterfaces.count |
|---|
| 999 | |
|---|
| 1000 | t = .memberwiseClone to Box |
|---|
| 1001 | assert t is not this |
|---|
| 1002 | _constructedTypes[key] = t |
|---|
| 1003 | argNames = (for type in typeArgs get type.name).join(',') |
|---|
| 1004 | t._name = '[.rootName]<of [argNames]>' |
|---|
| 1005 | t._genericDef = this |
|---|
| 1006 | t._nativeType = nil # The constructed type is really sourced from the generic def. Don't foster confusion with a reference to the original generic def's clr type (if there is one). |
|---|
| 1007 | t.cloneCollections |
|---|
| 1008 | |
|---|
| 1009 | # set the contructed type args immediately or its ancestors will get the original generic args during _bindInt: |
|---|
| 1010 | for i in typeArgs.count |
|---|
| 1011 | t._genericParams[i] = typeArgs[i] |
|---|
| 1012 | assert t._constructedTypes is nil or t._constructedTypes.count == 0 |
|---|
| 1013 | |
|---|
| 1014 | if .didBindInt, t._completeConstruction(typeArgs) |
|---|
| 1015 | else, t._needsConstruction(typeArgs) |
|---|
| 1016 | assert t._constructedTypes is nil or t._constructedTypes.count == 0 |
|---|
| 1017 | |
|---|
| 1018 | return t |
|---|
| 1019 | |
|---|
| 1020 | var _needs_typeArgs as List<of IType>? |
|---|
| 1021 | """ |
|---|
| 1022 | When non-nil, this box is constructed from a generic *and* requires completion of its construction of members. |
|---|
| 1023 | """ |
|---|
| 1024 | |
|---|
| 1025 | def completeMemberConstructionIfNeeded |
|---|
| 1026 | if _needs_typeArgs |
|---|
| 1027 | assert not .isGenericDef |
|---|
| 1028 | if not .didBindInt and not .isBindingInt |
|---|
| 1029 | .bindInt # this is required when inheriting from a constructed type such as "class Foo inherits List<of int>". Since "bind inheritance" happens prior to "bind interface", the base type will have been partially constructed without ever binding int. |
|---|
| 1030 | # TODO: compiler gives false warning for next line. see http://cobra-language.com/trac/cobra/ticket/41 |
|---|
| 1031 | if _needs_typeArgs # .no-warnings. |
|---|
| 1032 | typeArgs = _needs_typeArgs |
|---|
| 1033 | _needs_typeArgs = nil |
|---|
| 1034 | _completeConstruction(typeArgs) |
|---|
| 1035 | |
|---|
| 1036 | get needsConstruction as bool |
|---|
| 1037 | return _needs_typeArgs is not nil |
|---|
| 1038 | |
|---|
| 1039 | def _needsConstruction(typeArgs as List<of IType>) |
|---|
| 1040 | require |
|---|
| 1041 | .genericParams.count == typeArgs.count |
|---|
| 1042 | body |
|---|
| 1043 | _needs_typeArgs = typeArgs |
|---|
| 1044 | |
|---|
| 1045 | def _completeConstruction(typeArgs as List<of IType>) |
|---|
| 1046 | """ |
|---|
| 1047 | When this method is called, this instance is a constructed type, but its members (such as methods and properties) are still those of its generic type def. |
|---|
| 1048 | This method creates new members that are like the generic ones, but with the constructed type arguments substituted in. |
|---|
| 1049 | `.foo(item as T)` becomes `.foo(item as int)` |
|---|
| 1050 | """ |
|---|
| 1051 | require |
|---|
| 1052 | .isConstructed |
|---|
| 1053 | .genericParams.count == typeArgs.count |
|---|
| 1054 | .didBindInt or .isBindingInt |
|---|
| 1055 | not .isGenericDef |
|---|
| 1056 | .genericDef |
|---|
| 1057 | .genericDef.didBindInt or .genericDef.isBindingInt |
|---|
| 1058 | body |
|---|
| 1059 | _genericDef.unNilReturnTypes(_genericDef to !) |
|---|
| 1060 | gpToType = TypeUtil.dictionaryOf(_genericDef.genericParams, typeArgs) |
|---|
| 1061 | |
|---|
| 1062 | if _baseClass, _baseClass = _baseClass.secondaryConstructedTypeFor(this, gpToType) to Class |
|---|
| 1063 | |
|---|
| 1064 | assert _baseInterfaceProxies.count == 0 or _baseInterfaceProxies.count == _baseInterfaces.count |
|---|
| 1065 | for i in _baseInterfaces.count |
|---|
| 1066 | _baseInterfaces[i] = _baseInterfaces[i].secondaryConstructedTypeFor(this, gpToType) to Interface |
|---|
| 1067 | |
|---|
| 1068 | # construct the declarations |
|---|
| 1069 | _overloads = List<of MemberOverload>() |
|---|
| 1070 | newDecls = List<of IBoxMember>() |
|---|
| 1071 | # hmmm, is it really necessary to do the nested boxes before the other members? |
|---|
| 1072 | for decl in _declsInOrder |
|---|
| 1073 | if decl inherits Box |
|---|
| 1074 | nd = decl.constructedTypeFor(typeArgs) to IBoxMember |
|---|
| 1075 | newDecls.add(nd) |
|---|
| 1076 | for decl in _declsInOrder |
|---|
| 1077 | if decl inherits BoxMember |
|---|
| 1078 | #if not decl.didBindInt # hops: fix for crash with generics and java before changeset 2576 |
|---|
| 1079 | # print 'dbg: ', decl.name |
|---|
| 1080 | # decl.bindInt |
|---|
| 1081 | nd = decl.constructedFor(this, gpToType) |
|---|
| 1082 | assert nd <> decl |
|---|
| 1083 | newDecls.add(nd) |
|---|
| 1084 | else if not decl inherits Box |
|---|
| 1085 | newDecls.add(nd) |
|---|
| 1086 | _declsInOrder = List<of IBoxMember>() |
|---|
| 1087 | _declsByName = Dictionary<of String, IBoxMember>() |
|---|
| 1088 | _declsByNameCI = Dictionary<of String, IBoxMember>() |
|---|
| 1089 | for decl in newDecls |
|---|
| 1090 | if _declsByName.containsKey(decl.name) |
|---|
| 1091 | overload = nil to MemberOverload? |
|---|
| 1092 | other = _declsByName[decl.name] |
|---|
| 1093 | if other inherits MemberOverload |
|---|
| 1094 | overload = other |
|---|
| 1095 | else if other implements IOverloadable |
|---|
| 1096 | overload = MemberOverload(other) |
|---|
| 1097 | .registerOverload(overload to !) |
|---|
| 1098 | else |
|---|
| 1099 | throw FallThroughException(other) |
|---|
| 1100 | overload.addMember(decl to IOverloadable) |
|---|
| 1101 | else |
|---|
| 1102 | _declsInOrder.add(decl) |
|---|
| 1103 | _declsByName[decl.name] = decl |
|---|
| 1104 | _declsByNameCI[decl.name.toLower] = decl |
|---|
| 1105 | # TODO: can this next statement can be axed since there is a separate "bind inheritance" phase? |
|---|
| 1106 | _finishOverloads |
|---|
| 1107 | |
|---|
| 1108 | def secondaryConstructedTypeFor(box as Box, gpToType as Dictionary<of GenericParam, IType>) as IType is override |
|---|
| 1109 | if _genericParams.count == 0 |
|---|
| 1110 | return this |
|---|
| 1111 | typeArgs = List<of IType>() |
|---|
| 1112 | params = .genericParams |
|---|
| 1113 | for param in params |
|---|
| 1114 | if param inherits GenericParam |
|---|
| 1115 | # doesn't work: |
|---|
| 1116 | # typeArgs.add(gpToType[param]) |
|---|
| 1117 | found as GenericParam? |
|---|
| 1118 | for key as dynamic in gpToType.keys |
|---|
| 1119 | if key.name == param.name |
|---|
| 1120 | found = key |
|---|
| 1121 | # The generic param may not be found because, for example, it's declared for a |
|---|
| 1122 | # generic method and what's being constructed is the containing type; hence the |
|---|
| 1123 | # method's additional generic parameters are still generic. |
|---|
| 1124 | # see Tests/240-generics/400-generic-methods |
|---|
| 1125 | if found, typeArgs.add(gpToType[found]) |
|---|
| 1126 | else, typeArgs.add(param) |
|---|
| 1127 | else |
|---|
| 1128 | typeArgs.add(param.secondaryConstructedTypeFor(box, gpToType)) |
|---|
| 1129 | if .isGenericDef |
|---|
| 1130 | return .constructedTypeFor(typeArgs) |
|---|
| 1131 | else |
|---|
| 1132 | assert .genericDef.isGenericDef # if this ever fails, we may just need to follow .genericDef back iteratively until we get to the real generic type def |
|---|
| 1133 | return .genericDef.constructedTypeFor(typeArgs) |
|---|
| 1134 | |
|---|
| 1135 | def cloneCollections |
|---|
| 1136 | base.cloneCollections |
|---|
| 1137 | _genericParams = List<of IType>(_genericParams) # TODO: Can I just say _genericParams.clone? Do I need the cast? |
|---|
| 1138 | _constructedTypes = nil |
|---|
| 1139 | _baseInterfaceProxies = List<of ITypeProxy>(_baseInterfaceProxies) |
|---|
| 1140 | _baseInterfaces = List<of Interface>(_baseInterfaces) |
|---|
| 1141 | # _overloads = List<of MemberOverload>(_overloads) # these will be recreated |
|---|
| 1142 | |
|---|
| 1143 | def typeForGenericParam(gp as GenericParam) as IType # TODO: is this needed for NilableType? |
|---|
| 1144 | """ |
|---|
| 1145 | Returns the specific type arg that corresponds to the given generic |
|---|
| 1146 | parameter. Used to match the generic params in method, properties, etc. against |
|---|
| 1147 | the actual types in a constructed type. |
|---|
| 1148 | """ |
|---|
| 1149 | require |
|---|
| 1150 | .isGeneric |
|---|
| 1151 | .genericParams.count |
|---|
| 1152 | body |
|---|
| 1153 | # TODO: When does this get called? Investigate this. |
|---|
| 1154 | return .genericParams[gp.index] |
|---|
| 1155 | |
|---|
| 1156 | get containsGenericParameters as bool |
|---|
| 1157 | for param in _genericParams |
|---|
| 1158 | if param inherits GenericParam |
|---|
| 1159 | return true |
|---|
| 1160 | if param inherits Box # CC: and <next if condition> |
|---|
| 1161 | if param.containsGenericParameters |
|---|
| 1162 | return true |
|---|
| 1163 | return false |
|---|
| 1164 | |
|---|
| 1165 | |
|---|
| 1166 | class ClassOrStruct inherits Box is abstract, partial |
|---|
| 1167 | """ |
|---|
| 1168 | The abstract base class for Class and Struct. |
|---|
| 1169 | """ |
|---|
| 1170 | |
|---|
| 1171 | var _addsProxies as List<of ITypeProxy> |
|---|
| 1172 | |
|---|
| 1173 | cue init(token as IToken, idToken as IToken, name as String, paramList as List<of IType>, isNames as String*, attribs as AttributeList, implementsNodes as List<of ITypeProxy>, addsProxies as List<of ITypeProxy>, docString as String?) |
|---|
| 1174 | base.init(token, idToken, name, paramList, isNames, attribs, implementsNodes, docString) |
|---|
| 1175 | _addsProxies = addsProxies |
|---|
| 1176 | |
|---|
| 1177 | def _bindInh |
|---|
| 1178 | # mixins act as interfaces (and more) |
|---|
| 1179 | for proxy in _addsProxies |
|---|
| 1180 | _baseInterfaceProxies.add(proxy) |
|---|
| 1181 | base._bindInh |
|---|
| 1182 | |
|---|
| 1183 | def _bindInt |
|---|
| 1184 | # inject mixins |
|---|
| 1185 | for interf in _baseInterfaces |
|---|
| 1186 | if interf inherits Mixin |
|---|
| 1187 | interf.injectInto(this) |
|---|
| 1188 | base._bindInt |
|---|
| 1189 | |
|---|
| 1190 | def _bindImp |
|---|
| 1191 | base._bindImp |
|---|
| 1192 | _checkForSuspiciousDefInit |
|---|
| 1193 | |
|---|
| 1194 | def _checkForSuspiciousDefInit |
|---|
| 1195 | """ |
|---|
| 1196 | If a class or struct has no explicit initializers and has a 'def init' and |
|---|
| 1197 | it is not an override, then give a warning. |
|---|
| 1198 | """ |
|---|
| 1199 | if .isFromBinaryLibrary, return |
|---|
| 1200 | # have an explicit initializer? |
|---|
| 1201 | found = false |
|---|
| 1202 | for decl in .declsInOrder |
|---|
| 1203 | if decl inherits Initializer and not (decl to Node).isImplicit |
|---|
| 1204 | found = true |
|---|
| 1205 | break |
|---|
| 1206 | if found, return |
|---|
| 1207 | # have a non-overriding 'def init'? |
|---|
| 1208 | found = false |
|---|
| 1209 | for decl in .declsInOrder |
|---|
| 1210 | if decl inherits Method |
|---|
| 1211 | if decl.name == 'init' and not decl.isOverride |
|---|
| 1212 | found = true |
|---|
| 1213 | break |
|---|
| 1214 | if found |
|---|
| 1215 | .compiler.warning(decl to ISyntaxNode, 'Did you mean "cue init"?') |
|---|
| 1216 | |
|---|
| 1217 | |
|---|
| 1218 | class Class |
|---|
| 1219 | is partial |
|---|
| 1220 | inherits ClassOrStruct |
|---|
| 1221 | |
|---|
| 1222 | var _baseNode as ITypeProxy? |
|---|
| 1223 | var _subclasses = List<of Class>() |
|---|
| 1224 | |
|---|
| 1225 | cue init(token as IToken, idToken as IToken, name as String, paramList as List<of IType>, isNames as String*, attribs as AttributeList, baseNode as ITypeProxy?, implementsNodes as List<of ITypeProxy>, addsProxies as List<of ITypeProxy>, docString as String?) |
|---|
| 1226 | base.init(token, idToken, name, paramList, isNames, attribs, implementsNodes, addsProxies, docString) |
|---|
| 1227 | _baseNode = baseNode |
|---|
| 1228 | |
|---|
| 1229 | cue init(name as String, paramList as List<of IType>) |
|---|
| 1230 | """ public skeleton class - init with given name and paramlist - no baseclass, attributes, interfaces or mixins.""" |
|---|
| 1231 | .init(Token.empty, Token.empty, name, paramList, ['public'], AttributeList(), nil, List<of ITypeProxy>(), List<of ITypeProxy>(), '') |
|---|
| 1232 | |
|---|
| 1233 | cue init(nativeType as NativeType, backend as BackEnd) |
|---|
| 1234 | # TODO: fix native |
|---|
| 1235 | base.init(TokenFix.empty, TokenFix.empty, backend.cobraNameForNativeBoxName(nativeType.name), List<of IType>(), List<of String>(), AttributeList(), List<of ITypeProxy>(), List<of ITypeProxy>(), nil) |
|---|
| 1236 | if nativeType.baseType |
|---|
| 1237 | _baseNode = backend.nativeTypeProxy(nativeType.baseType to !) |
|---|
| 1238 | # to-do: keep the following? error? assertion |
|---|
| 1239 | # else if nativeType.name <> 'Object' |
|---|
| 1240 | # print 'No baseType for [nativeType.name]' |
|---|
| 1241 | _initNativeType(nativeType) |
|---|
| 1242 | |
|---|
| 1243 | def addRefFields |
|---|
| 1244 | base.addRefFields |
|---|
| 1245 | .addField('baseNode', _baseNode) |
|---|
| 1246 | |
|---|
| 1247 | get isCallable as bool is override |
|---|
| 1248 | return true |
|---|
| 1249 | |
|---|
| 1250 | def isDescendantOf(type as IType) as bool is override |
|---|
| 1251 | or require .nativeType |
|---|
| 1252 | _prepLibraryBox |
|---|
| 1253 | if this == type, return true |
|---|
| 1254 | if not .baseClass and _baseNode, .bindInh |
|---|
| 1255 | if .compiler, type.bindInh |
|---|
| 1256 | if type inherits Interface |
|---|
| 1257 | if .isDescendantOfInterface(type) |
|---|
| 1258 | return true |
|---|
| 1259 | baseClass = .baseClass |
|---|
| 1260 | assert baseClass is not this # check for direct cycles |
|---|
| 1261 | if baseClass, return baseClass.isDescendantOf(type) |
|---|
| 1262 | return false |
|---|
| 1263 | |
|---|
| 1264 | get isReference as bool is override |
|---|
| 1265 | return true |
|---|
| 1266 | |
|---|
| 1267 | get subclasses from var |
|---|
| 1268 | |
|---|
| 1269 | pro baseNode from var |
|---|
| 1270 | |
|---|
| 1271 | def declForName(name as String) as IBoxMember? is override |
|---|
| 1272 | """ |
|---|
| 1273 | Handle get/set parts like "someProp.get" or "[].set" |
|---|
| 1274 | `computeMatchingBaseMember` in Members.cobra is at least one that returns this. |
|---|
| 1275 | """ |
|---|
| 1276 | m = base.declForName(name) |
|---|
| 1277 | if m is nil and '.' in name |
|---|
| 1278 | isProperty = true |
|---|
| 1279 | if name.endsWith('.get'), part = 'g' |
|---|
| 1280 | else if name.endsWith('.set'), part = 's' |
|---|
| 1281 | else, isProperty = false # example: 'System.Collections.IList.IsFixedSize' |
|---|
| 1282 | if isProperty |
|---|
| 1283 | pd = .memberForName(name[:-4]) |
|---|
| 1284 | if pd inherits ProperDexer |
|---|
| 1285 | branch part |
|---|
| 1286 | on 'g', m = pd.getPart |
|---|
| 1287 | on 's', m = pd.setPart |
|---|
| 1288 | # TODO: cache the above back into the _decls |
|---|
| 1289 | # TODO: ? else, throw FallThroughException(...) |
|---|
| 1290 | return m |
|---|
| 1291 | |
|---|
| 1292 | var _hackCheck = false |
|---|
| 1293 | |
|---|
| 1294 | def memberForName(name as String) as IMember? |
|---|
| 1295 | # the next assertion fails for Tests\600-misc\404-implement-IEnumerable |
|---|
| 1296 | # could not fix. I'm confused. Something to do with generics. So bail on generics: |
|---|
| 1297 | # asserting .didBindInt is difficult because .memberForName gets invoked during bindInt |
|---|
| 1298 | # if not .isGeneric |
|---|
| 1299 | # assert .didBindInt # TODO: is this legit? if so, push up to Container |
|---|
| 1300 | # TODO: assert .didBindInh |
|---|
| 1301 | |
|---|
| 1302 | if not _hackCheck |
|---|
| 1303 | _hackCheck = true |
|---|
| 1304 | if _nativeType and .name == 'String' and .parentNameSpace and .parentNameSpace.name == 'System' and name <> 'repeat' |
|---|
| 1305 | # Address the problem where `s.split(sep, 2)` binds to the wrong .split and therefore generates the wrong code. |
|---|
| 1306 | # The real fix is deeper and won't be done just now. to-do |
|---|
| 1307 | .memberForName('repeat') |
|---|
| 1308 | |
|---|
| 1309 | m = base.memberForName(name) |
|---|
| 1310 | if m is nil and _baseClass, m = _baseClass.memberForName(name) |
|---|
| 1311 | if m is nil, m = .interfaceMemberForName(name) |
|---|
| 1312 | return m |
|---|
| 1313 | |
|---|
| 1314 | def _bindBase is override |
|---|
| 1315 | if _baseNode |
|---|
| 1316 | possible = _baseNode.realType |
|---|
| 1317 | baseName = if(_baseNode inherits AbstractTypeIdentifier, (_baseNode to AbstractTypeIdentifier).name, nil) # CC: if-inherits should work for expressions too |
|---|
| 1318 | if possible inherits Class |
|---|
| 1319 | _baseClass = possible |
|---|
| 1320 | else if possible inherits Interface |
|---|
| 1321 | assert baseName |
|---|
| 1322 | .throwError('The base "[baseName]" is an interface. Try "implements" instead of "inherits".') |
|---|
| 1323 | else if possible inherits Struct |
|---|
| 1324 | assert baseName |
|---|
| 1325 | .throwError('The base "[baseName]" is a struct. Classes cannot inherit from structs.') |
|---|
| 1326 | else |
|---|
| 1327 | assert baseName |
|---|
| 1328 | .throwError('The base class "[baseName]" is not actually a class, it is a "[possible.englishName]".') |
|---|
| 1329 | else |
|---|
| 1330 | t = .compiler.objectType to Class |
|---|
| 1331 | if this is not t # don't want Object to inherit Object |
|---|
| 1332 | _baseClass = t |
|---|
| 1333 | if _baseClass |
|---|
| 1334 | _baseClass._subclasses.add(this) |
|---|
| 1335 | |
|---|
| 1336 | def _bindInt |
|---|
| 1337 | # Note that the _baseClass is not told to bindInt. That would fail for classes in other namespaces and it's unnecessary |
|---|
| 1338 | base._bindInt |
|---|
| 1339 | if .isDescendantOf(.compiler.attributeType) and not .name.endsWith('Attribute') |
|---|
| 1340 | .compiler.warning(this, 'When attributes are declared, they should be suffixed with "Attribute".') |
|---|
| 1341 | |
|---|
| 1342 | def _badInterfaceError(type as IType) is override |
|---|
| 1343 | msg = 'Cannot implement "[type.name]" which is a [type.englishName].' |
|---|
| 1344 | if type inherits Class, msg += ' Use "inherits" instead.' |
|---|
| 1345 | .throwError(msg) |
|---|
| 1346 | |
|---|
| 1347 | def _makeInitializers |
|---|
| 1348 | base._makeInitializers |
|---|
| 1349 | |
|---|
| 1350 | for decl in .declsInOrder, if decl inherits Initializer, return |
|---|
| 1351 | |
|---|
| 1352 | if .compiler.options.boolValue('legacy-one-default-initializer') |
|---|
| 1353 | init = Initializer(.token, Token.empty, this, List<of Param>(), ['public'], AttributeList(), '', isImplicit=true) |
|---|
| 1354 | init.addStmt(DotExpr(.token.copy('DOT', '.'), 'DOT', BaseLit(.token.copy('BASE', 'base')), MemberExpr(.token.copy('ID', 'init')))) |
|---|
| 1355 | .addDecl(init) |
|---|
| 1356 | else |
|---|
| 1357 | # provide every initializer from the base class |
|---|
| 1358 | count = 0 |
|---|
| 1359 | firstInit as Initializer? |
|---|
| 1360 | .baseClass.prepIfNeeded |
|---|
| 1361 | isFromBinaryLibrary = .baseClass.isFromBinaryLibrary |
|---|
| 1362 | inits = List<of Initializer>() |
|---|
| 1363 | for decl in .baseClass.declsInOrder |
|---|
| 1364 | if decl inherits Initializer |
|---|
| 1365 | if decl.isPrivate, continue |
|---|
| 1366 | if isFromBinaryLibrary and not decl.isPublic and not decl.isProtected, continue |
|---|
| 1367 | if decl.isPublic or decl.isProtected |
|---|
| 1368 | init = Initializer(.token, Token.empty, this, decl.params.clone, decl.isNames, decl.attributes, '', isImplicit=true) |
|---|
| 1369 | inits.add(init) |
|---|
| 1370 | if decl.params.count == 0 |
|---|
| 1371 | dotRight = MemberExpr(.token.copy('ID', 'init')) to Expr |
|---|
| 1372 | else |
|---|
| 1373 | args = for param in decl.params get IdentifierExpr(.token.copy('ID', param.name), param.name) to Expr |
|---|
| 1374 | dotRight = CallExpr(.token.copy('ID', 'init'), 'init', args, true) |
|---|
| 1375 | init.addStmt(DotExpr(.token.copy('DOT', '.'), 'DOT', BaseLit(.token.copy('BASE', 'base')), dotRight)) |
|---|
| 1376 | if count == 0 |
|---|
| 1377 | .addDecl(init) |
|---|
| 1378 | firstInit = init |
|---|
| 1379 | else if count == 1 |
|---|
| 1380 | overload = MemberOverload(firstInit) |
|---|
| 1381 | .registerOverload(overload) |
|---|
| 1382 | overload.addMember(init) |
|---|
| 1383 | else |
|---|
| 1384 | overload.addMember(init) |
|---|
| 1385 | count += 1 |
|---|
| 1386 | # System.Attribute's initializer is protected, making it awkward if a subclass does not define one. Therefore: |
|---|
| 1387 | if inits.count == 1 and inits[0].params.count == 0 and not inits[0].isPublic |
|---|
| 1388 | inits[0].changeToPublic |
|---|
| 1389 | # System.Collections.ObjectModel.KeyedCollection<of TKey, TValue> is also awkward as all of its initializers are protected |
|---|
| 1390 | else if inits.count > 1 |
|---|
| 1391 | hasPublic = false |
|---|
| 1392 | for init in inits |
|---|
| 1393 | if init.isPublic |
|---|
| 1394 | hasPublic = true |
|---|
| 1395 | break |
|---|
| 1396 | if not hasPublic |
|---|
| 1397 | for init in inits |
|---|
| 1398 | if init.params.count == 0 |
|---|
| 1399 | init.changeToPublic |
|---|
| 1400 | break |
|---|
| 1401 | |
|---|
| 1402 | get isSystemObjectClass as bool is override |
|---|
| 1403 | return _nativeType and _nativeType.isSystemObjectClass |
|---|
| 1404 | |
|---|
| 1405 | get isSystemTypeClass as bool is override |
|---|
| 1406 | return _nativeType and _nativeType.isSystemTypeClass |
|---|
| 1407 | |
|---|
| 1408 | def _finishOverloads |
|---|
| 1409 | # deal with inheritance and overloads |
|---|
| 1410 | assert _baseClass or .isSystemObjectClass |
|---|
| 1411 | if _baseClass |
|---|
| 1412 | #assert _baseClass.didBindInt |
|---|
| 1413 | for decl in List<of IBoxMember>(_declsInOrder) |
|---|
| 1414 | if decl inherits Method and not decl inherits Initializer # TODO: I don't think this captures Indexers. Make a test case if needed, write: if decl.canBeOverloaded or if decl inherits ICanBeOverloaded |
|---|
| 1415 | other = _baseClass.memberForName(decl.name) |
|---|
| 1416 | if other |
|---|
| 1417 | if decl inherits MemberOverload |
|---|
| 1418 | overload = decl |
|---|
| 1419 | else if decl implements IOverloadable |
|---|
| 1420 | overload = MemberOverload(decl) |
|---|
| 1421 | .registerOverload(overload) |
|---|
| 1422 | else |
|---|
| 1423 | throw FallThroughException(decl) |
|---|
| 1424 | if other inherits MemberOverload |
|---|
| 1425 | for member in other.members |
|---|
| 1426 | overload.addInheritedMemberIfNoMatch(member) |
|---|
| 1427 | else if other inherits IOverloadable |
|---|
| 1428 | overload.addInheritedMemberIfNoMatch(other) |
|---|
| 1429 | else |
|---|
| 1430 | decl.recordError('Cannot declare a [decl.englishName] named "[decl.name]" because the base member "[decl.name]" is a [other.englishName].') |
|---|
| 1431 | base._finishOverloads |
|---|
| 1432 | |
|---|
| 1433 | get englishName as String is override |
|---|
| 1434 | return 'class' |
|---|
| 1435 | |
|---|
| 1436 | |
|---|
| 1437 | class Mixin |
|---|
| 1438 | is partial |
|---|
| 1439 | inherits Interface |
|---|
| 1440 | |
|---|
| 1441 | # Hilarious! The implementation of Mixin would benefit from having mixins in the language |
|---|
| 1442 | # because we need them for class, struct and mixin, but not for interfaces. Awesome! :-) |
|---|
| 1443 | |
|---|
| 1444 | cue init(token as IToken, idToken as IToken, name as String, paramList as List<of IType>, isNames as String*, attribs as AttributeList, baseNode as ITypeProxy?, implementsNodes as List<of ITypeProxy>, addsProxies as List<of ITypeProxy>, docString as String?) |
|---|
| 1445 | base.init(token, idToken, name, paramList, isNames, attribs, implementsNodes, docString) |
|---|
| 1446 | # there are restrictions on mixins which may be relaxed in the future |
|---|
| 1447 | assert baseNode is nil |
|---|
| 1448 | assert implementsNodes.count == 0 |
|---|
| 1449 | assert addsProxies.count == 0 |
|---|
| 1450 | _addsProxies = addsProxies |
|---|
| 1451 | |
|---|
| 1452 | var _canHaveStatements = true |
|---|
| 1453 | |
|---|
| 1454 | get canHaveStatements as bool is override |
|---|
| 1455 | return _canHaveStatements |
|---|
| 1456 | |
|---|
| 1457 | var _addsProxies as List<of ITypeProxy> |
|---|
| 1458 | |
|---|
| 1459 | def _bindInt |
|---|
| 1460 | # mixins act as interfaces (and more) |
|---|
| 1461 | for proxy in _addsProxies |
|---|
| 1462 | _baseInterfaceProxies.add(proxy) |
|---|
| 1463 | base._bindInt |
|---|
| 1464 | |
|---|
| 1465 | def injectInto(box as Box) |
|---|
| 1466 | for member in .declsInOrder # TODO: deal with inheritance if mixins are allowed to have mixins added to them |
|---|
| 1467 | # TODO: deal with overloads |
|---|
| 1468 | if member inherits Method |
|---|
| 1469 | method = Method(member.token, member.idToken, box, member.name, member.genericParams, member.params, member.resultType, nil/#implementsTypeNode#/, member.isNames, member.attributes, member.docString) |
|---|
| 1470 | # TODO: contracts? tests? |
|---|
| 1471 | for stmt in member.statements |
|---|
| 1472 | method.addStmt(stmt.clone) |
|---|
| 1473 | box.addDecl(method) |
|---|
| 1474 | else if member inherits Property |
|---|
| 1475 | prop = Property(member.token, member.idToken, box, member.name, member.returnType, member.isNames, member.attributes, member.docString) |
|---|
| 1476 | if member.getPart |
|---|
| 1477 | getPart = prop.makeGetPart(member.getPart.token) |
|---|
| 1478 | for stmt in member.getPart.statements |
|---|
| 1479 | getPart.addStmt(stmt.clone) |
|---|
| 1480 | if member.setPart |
|---|
| 1481 | setPart = prop.makeSetPart(member.setPart.token) |
|---|
| 1482 | for stmt in member.setPart.statements |
|---|
| 1483 | setPart.addStmt(stmt.clone) |
|---|
| 1484 | box.addDecl(prop) |
|---|
| 1485 | else if member inherits BoxField |
|---|
| 1486 | box.addDecl(member) |
|---|
| 1487 | else |
|---|
| 1488 | # TODO: warning? |
|---|
| 1489 | pass |
|---|
| 1490 | |
|---|
| 1491 | |
|---|
| 1492 | class Interface |
|---|
| 1493 | is partial |
|---|
| 1494 | inherits Box |
|---|
| 1495 | |
|---|
| 1496 | cue init(token as IToken, idToken as IToken, name as String, paramList as List<of IType>, isNames as String*, attribs as AttributeList, baseNodes as List<of ITypeProxy>, docString as String?) |
|---|
| 1497 | base.init(token, idToken, name, paramList, isNames, attribs, baseNodes, docString) |
|---|
| 1498 | |
|---|
| 1499 | cue init(nativeType as NativeType, backend as BackEnd) |
|---|
| 1500 | base.init(TokenFix.empty, TokenFix.empty, backend.cobraNameForNativeBoxName(nativeType.name), List<of IType>(), List<of String>(), AttributeList(), List<of ITypeProxy>(), nil) |
|---|
| 1501 | _initNativeType(nativeType) |
|---|
| 1502 | |
|---|
| 1503 | get canHaveStatements as bool is override |
|---|
| 1504 | return false |
|---|
| 1505 | |
|---|
| 1506 | get englishName as String is override |
|---|
| 1507 | return 'interface' |
|---|
| 1508 | |
|---|
| 1509 | get isReference as bool is override |
|---|
| 1510 | return true |
|---|
| 1511 | |
|---|
| 1512 | def isDescendantOf(type as IType) as bool is override |
|---|
| 1513 | or require .nativeType |
|---|
| 1514 | _prepLibraryBox |
|---|
| 1515 | if this == type, return true |
|---|
| 1516 | if type inherits Interface |
|---|
| 1517 | if .isDescendantOfInterface(type) |
|---|
| 1518 | return true |
|---|
| 1519 | if .superType is type or .superType.isDescendantOf(type), return true |
|---|
| 1520 | return false |
|---|
| 1521 | |
|---|
| 1522 | def memberForName(name as String) as IMember? |
|---|
| 1523 | m = base.memberForName(name) |
|---|
| 1524 | if m is nil |
|---|
| 1525 | m = .interfaceMemberForName(name) |
|---|
| 1526 | if m is nil and _baseClass |
|---|
| 1527 | m = _baseClass.memberForName(name) |
|---|
| 1528 | return m |
|---|
| 1529 | |
|---|
| 1530 | |
|---|
| 1531 | class Struct |
|---|
| 1532 | is partial |
|---|
| 1533 | inherits ClassOrStruct |
|---|
| 1534 | |
|---|
| 1535 | cue init(token as IToken, idToken as IToken, name as String, paramList as List<of IType>, isNames as String*, attribs as AttributeList, baseName as String?, interfaceNodes as List<of ITypeProxy>, addsProxies as List<of ITypeProxy>, docString as String?) |
|---|
| 1536 | base.init(token, idToken, name, paramList, isNames, attribs, interfaceNodes, addsProxies, docString) |
|---|
| 1537 | |
|---|
| 1538 | cue init(nativeType as NativeType, backend as BackEnd) |
|---|
| 1539 | base.init(TokenFix.empty, TokenFix.empty, backend.cobraNameForNativeBoxName(nativeType.name), List<of IType>(), List<of String>(), AttributeList(), List<of ITypeProxy>(), List<of ITypeProxy>(), nil) |
|---|
| 1540 | _initNativeType(nativeType) |
|---|
| 1541 | |
|---|
| 1542 | get englishName as String is override |
|---|
| 1543 | return 'struct' |
|---|
| 1544 | |
|---|
| 1545 | def isDescendantOf(type as IType) as bool is override |
|---|
| 1546 | # TODO: hmmm, almost duplicated from Class |
|---|
| 1547 | or require .nativeType |
|---|
| 1548 | _prepLibraryBox |
|---|
| 1549 | if this == type, return true |
|---|
| 1550 | if not .baseClass /# TODO? and _baseNode #/, .bindInh |
|---|
| 1551 | if .compiler, type.bindInh |
|---|
| 1552 | if type inherits Interface |
|---|
| 1553 | if .isDescendantOfInterface(type) |
|---|
| 1554 | return true |
|---|
| 1555 | baseClass = .baseClass |
|---|
| 1556 | # assert baseClass is not this, this # check for direct cycles |
|---|
| 1557 | if baseClass, return baseClass.isDescendantOf(type) |
|---|
| 1558 | return false |
|---|
| 1559 | |
|---|
| 1560 | get isCallable as bool is override |
|---|
| 1561 | return true |
|---|
| 1562 | |
|---|
| 1563 | get isReference as bool is override |
|---|
| 1564 | return false |
|---|
| 1565 | |
|---|
| 1566 | def memberForName(name as String) as IMember? |
|---|
| 1567 | m = base.memberForName(name) |
|---|
| 1568 | if m is nil and _baseClass |
|---|
| 1569 | m = _baseClass.memberForName(name) |
|---|
| 1570 | return m |
|---|
| 1571 | |
|---|
| 1572 | def _makeInitializers |
|---|
| 1573 | base._makeInitializers |
|---|
| 1574 | if .isFromBinaryLibrary, return |
|---|
| 1575 | # Check for explicit parameterless inits which are disallowed in structs |
|---|
| 1576 | hasParameterlessInit = false |
|---|
| 1577 | for decl in .declsInOrder |
|---|
| 1578 | if decl inherits Initializer |
|---|
| 1579 | if not decl.hasParams |
|---|
| 1580 | decl.recordError('Structs cannot contain explicit parameterless initializers. A default one is provided.') |
|---|
| 1581 | hasParameterlessInit = true |
|---|
| 1582 | # Create the implicit parameterless init |
|---|
| 1583 | if hasParameterlessInit, return |
|---|
| 1584 | init = Initializer(.token, .token, this, List<of Param>(), ['public'], AttributeList(), 'Default struct initializer.', isImplicit = true) |
|---|
| 1585 | other = .declForName('cue.init') |
|---|
| 1586 | overload = nil to MemberOverload? |
|---|
| 1587 | if other inherits MemberOverload |
|---|
| 1588 | overload = other |
|---|
| 1589 | else if other |
|---|
| 1590 | overload = MemberOverload(other to IOverloadable) |
|---|
| 1591 | .registerOverload(overload to !) |
|---|
| 1592 | else |
|---|
| 1593 | .addDecl(init) |
|---|
| 1594 | if overload, overload.addMember(init) |
|---|
| 1595 | |
|---|
| 1596 | |
|---|
| 1597 | class MethodSig inherits Class is partial |
|---|
| 1598 | """ |
|---|
| 1599 | Example Cobra source: |
|---|
| 1600 | sig ComputeSomething(a is int, b as int) as int |
|---|
| 1601 | |
|---|
| 1602 | .NET calls these delegates and describes them as type-safe method signatures. |
|---|
| 1603 | The "sig" keyword fits nicely with other declaration keywords like "var" "def" and "get". |
|---|
| 1604 | And "sig" is a more platform neutral term should we have other non-CLI backends. |
|---|
| 1605 | |
|---|
| 1606 | MethodSigs are only created when parsing. When reading from a DLL, delegates are merely |
|---|
| 1607 | subclasses of Delegate or MulticastDelegate. |
|---|
| 1608 | |
|---|
| 1609 | Note that MethodSig is a subclass of Class and therefore both a Box and an IType. Also, it will |
|---|
| 1610 | return true for .isDescendantOf(.compiler.delegateType). |
|---|
| 1611 | |
|---|
| 1612 | Reference: Pro C# 2008, Chapter 11 |
|---|
| 1613 | """ |
|---|
| 1614 | |
|---|
| 1615 | var _params as List<of Param> |
|---|
| 1616 | var _returnTypeProxy as ITypeProxy |
|---|
| 1617 | var _returnType as IType? |
|---|
| 1618 | |
|---|
| 1619 | cue init(token as IToken, idToken as IToken, parent as IParentSpace?, name as String, params as List<of Param>, returnTypeProxy as ITypeProxy, isNames as String*, attribs as AttributeList, docString as String) |
|---|
| 1620 | base.init(token, idToken, name, List<of IType>(), isNames, attribs, LibraryTypeProxy('System.MulticastDelegate'), List<of ITypeProxy>(), List<of ITypeProxy>(), docString) |
|---|
| 1621 | _initParent(parent) |
|---|
| 1622 | _params = params |
|---|
| 1623 | _returnTypeProxy = returnTypeProxy |
|---|
| 1624 | |
|---|
| 1625 | get params from var |
|---|
| 1626 | |
|---|
| 1627 | get returnTypeProxy from var |
|---|
| 1628 | |
|---|
| 1629 | get returnType from var |
|---|
| 1630 | |
|---|
| 1631 | get resultType as IType? is override |
|---|
| 1632 | return .returnType |
|---|
| 1633 | |
|---|
| 1634 | def _bindInh |
|---|
| 1635 | base._bindInh |
|---|
| 1636 | assert _baseClass |
|---|
| 1637 | assert _baseClass.qualifiedName == 'System.MulticastDelegate' |
|---|
| 1638 | assert .parentBox or .parentNameSpace |
|---|
| 1639 | |
|---|
| 1640 | def _bindInt |
|---|
| 1641 | returnType as ITypeProxy = .returnType ? .returnTypeProxy |
|---|
| 1642 | .addDecl(_makeMethod('invoke', .params.clone, returnType)) |
|---|
| 1643 | # dynamic type vari length param in list as placeholder for multiple params |
|---|
| 1644 | params = [Param('vParam', VariTypeIdentifier(.token, TypeIdentifier(.token, DynamicType())))] |
|---|
| 1645 | .addDecl(_makeMethod('beginInvoke', params, TypeIdentifier(.token.copy('ID', 'IAsyncResult')) to ITypeProxy)) |
|---|
| 1646 | .addDecl(_makeMethod('endInvoke', params, returnType )) |
|---|
| 1647 | base._bindInt |
|---|
| 1648 | for param in .params |
|---|
| 1649 | param.bindInt |
|---|
| 1650 | if not _returnType |
|---|
| 1651 | _returnType = _returnTypeProxy.realType |
|---|
| 1652 | |
|---|
| 1653 | def _makeInitializers is override |
|---|
| 1654 | pass |
|---|
| 1655 | |
|---|
| 1656 | def _makeMethod(name as String, params as IList<of Param>, returnTypeProxy as ITypeProxy) as Method |
|---|
| 1657 | m = Method(.token, .token, this, name, params, returnTypeProxy, nil, .isNames, AttributeList(), '') |
|---|
| 1658 | # method body just to avoid a Cobra warning during .bindImp |
|---|
| 1659 | m.statements.add(ThrowStmt(.token, PostCallExpr(.token, IdentifierExpr(.token, 'Exception'), List<of Expr>()))) |
|---|
| 1660 | return m |
|---|
| 1661 | |
|---|
| 1662 | class GenericParam inherits CobraType is partial |
|---|
| 1663 | """ |
|---|
| 1664 | A generic parameter *is* a type. |
|---|
| 1665 | """ |
|---|
| 1666 | |
|---|
| 1667 | var _name as String |
|---|
| 1668 | var _constraints as List<of GenericConstraint> |
|---|
| 1669 | var _index as int |
|---|
| 1670 | var _objectClass as Class? |
|---|
| 1671 | var _nativeType as NativeType? |
|---|
| 1672 | |
|---|
| 1673 | cue init(name as String) |
|---|
| 1674 | require name.length |
|---|
| 1675 | base.init |
|---|
| 1676 | _name = name |
|---|
| 1677 | _constraints = List<of GenericConstraint>() |
|---|
| 1678 | |
|---|
| 1679 | cue init(genArgType as NativeType) |
|---|
| 1680 | .init(genArgType.name) |
|---|
| 1681 | _nativeType = genArgType |
|---|
| 1682 | # TODO: scan Constraints |
|---|
| 1683 | |
|---|
| 1684 | get constraints from var |
|---|
| 1685 | |
|---|
| 1686 | get englishName as String is override |
|---|
| 1687 | return 'generic parameter' |
|---|
| 1688 | |
|---|
| 1689 | get idString as String is override |
|---|
| 1690 | return '[.getType.name]([.serialNum], "[.name]")' |
|---|
| 1691 | |
|---|
| 1692 | pro index from var |
|---|
| 1693 | |
|---|
| 1694 | get isReference as bool is override |
|---|
| 1695 | # Well, it's hard to say if a GenericParam is a reference or value type, but CompareExpr() influences us to say "true". |
|---|
| 1696 | # TODO: if there are constraints on the generic param, examine them to determine answer |
|---|
| 1697 | return true |
|---|
| 1698 | |
|---|
| 1699 | get isUninitializedForLocalVars as bool is override |
|---|
| 1700 | return false # TODO: could use a more sophisticated implementation |
|---|
| 1701 | |
|---|
| 1702 | get name as String is override |
|---|
| 1703 | return _name |
|---|
| 1704 | |
|---|
| 1705 | get nativeType from var |
|---|
| 1706 | |
|---|
| 1707 | pro parentDefinition from var as NamedNode? |
|---|
| 1708 | """ |
|---|
| 1709 | The definition that directly contains this generic parameter. |
|---|
| 1710 | For example, if non-nil, then `gp in .parentDefinition.genericParams` will be true. |
|---|
| 1711 | GenericParams are created in other circumstances such as being passed into a constructed type, in which case .parentDefinition will be nil. |
|---|
| 1712 | Note that .parentDefinition is always a Box or a Method. # TODO: require/ensure that? |
|---|
| 1713 | """ |
|---|
| 1714 | |
|---|
| 1715 | def addMinFields |
|---|
| 1716 | base.addMinFields |
|---|
| 1717 | .addField('name', _name) |
|---|
| 1718 | |
|---|
| 1719 | def addSubFields |
|---|
| 1720 | base.addSubFields |
|---|
| 1721 | .addField('constraints', _constraints) |
|---|
| 1722 | .addField('index', _index) |
|---|
| 1723 | |
|---|
| 1724 | def declForName(name as String) as IMember? is override |
|---|
| 1725 | for constraint in _constraints |
|---|
| 1726 | decl = constraint.declForName(name) |
|---|
| 1727 | if decl |
|---|
| 1728 | return decl |
|---|
| 1729 | return _objectClass.declForName(name) |
|---|
| 1730 | |
|---|
| 1731 | def memberForName(name as String) as IMember? is override |
|---|
| 1732 | for constraint in _constraints |
|---|
| 1733 | member = constraint.memberForName(name) |
|---|
| 1734 | if member |
|---|
| 1735 | return member |
|---|
| 1736 | return _objectClass.memberForName(name) |
|---|
| 1737 | |
|---|
| 1738 | def isDescendantOf(type as IType) as bool is override |
|---|
| 1739 | if this == type, return true |
|---|
| 1740 | if type is .compiler.objectType, return true |
|---|
| 1741 | if type.superType is nil, return true # the root type |
|---|
| 1742 | for constraint in _constraints |
|---|
| 1743 | if constraint.isDescendantOf(type) |
|---|
| 1744 | return true |
|---|
| 1745 | return false |
|---|
| 1746 | |
|---|
| 1747 | def secondaryConstructedTypeFor(box as Box, gpToType as Dictionary<of GenericParam, IType>) as IType is override |
|---|
| 1748 | if gpToType.containsKey(this) |
|---|
| 1749 | return gpToType[this] |
|---|
| 1750 | for key in gpToType.keys |
|---|
| 1751 | if key.name == .name |
|---|
| 1752 | return gpToType[key] |
|---|
| 1753 | # a generic method in a generic class requires the next statement |
|---|
| 1754 | # see Tests/240-generics/400-generic-methods/102-generic-method-in-generic-class.cobra |
|---|
| 1755 | return this |
|---|
| 1756 | |
|---|
| 1757 | def _bindInt |
|---|
| 1758 | base._bindInt |
|---|
| 1759 | _objectClass = .compiler.objectClass |
|---|
| 1760 | for constraint in _constraints |
|---|
| 1761 | constraint.bindInt |
|---|
| 1762 | |
|---|
| 1763 | |
|---|
| 1764 | class GenericConstraint |
|---|
| 1765 | inherits SyntaxNode |
|---|
| 1766 | |
|---|
| 1767 | cue init(token as IToken) |
|---|
| 1768 | base.init(token) |
|---|
| 1769 | |
|---|
| 1770 | def isDescendantOf(type as IType) as bool |
|---|
| 1771 | return false |
|---|
| 1772 | |
|---|
| 1773 | def declForName(name as String) as IBoxMember? |
|---|
| 1774 | """ |
|---|
| 1775 | Returns nil by default. |
|---|
| 1776 | """ |
|---|
| 1777 | return nil |
|---|
| 1778 | |
|---|
| 1779 | def memberForName(name as String) as IMember? |
|---|
| 1780 | """ |
|---|
| 1781 | Returns nil by default. |
|---|
| 1782 | """ |
|---|
| 1783 | return nil |
|---|
| 1784 | |
|---|
| 1785 | def _bindInt |
|---|
| 1786 | base._bindInt |
|---|
| 1787 | |
|---|
| 1788 | |
|---|
| 1789 | class GenericClassConstraint |
|---|
| 1790 | is partial |
|---|
| 1791 | inherits GenericConstraint |
|---|
| 1792 | """ |
|---|
| 1793 | Represents the generic constraint class |
|---|
| 1794 | """ |
|---|
| 1795 | |
|---|
| 1796 | cue init(token as IToken) |
|---|
| 1797 | base.init(token) |
|---|
| 1798 | |
|---|
| 1799 | |
|---|
| 1800 | class GenericStructConstraint |
|---|
| 1801 | is partial |
|---|
| 1802 | inherits GenericConstraint |
|---|
| 1803 | """ |
|---|
| 1804 | Represents the generic constraint class |
|---|
| 1805 | """ |
|---|
| 1806 | |
|---|
| 1807 | cue init(token as IToken) |
|---|
| 1808 | base.init(token) |
|---|
| 1809 | |
|---|
| 1810 | |
|---|
| 1811 | class GenericCallableConstraint |
|---|
| 1812 | is partial |
|---|
| 1813 | inherits GenericConstraint |
|---|
| 1814 | """ |
|---|
| 1815 | Represents the generic constraint callable |
|---|
| 1816 | """ |
|---|
| 1817 | |
|---|
| 1818 | cue init(token as IToken) |
|---|
| 1819 | base.init(token) |
|---|
| 1820 | |
|---|
| 1821 | |
|---|
| 1822 | class GenericTypeConstraint |
|---|
| 1823 | is partial |
|---|
| 1824 | inherits GenericConstraint |
|---|
| 1825 | """ |
|---|
| 1826 | Represents the generic constraint of a particular type. |
|---|
| 1827 | """ |
|---|
| 1828 | |
|---|
| 1829 | var _representedType as IType? |
|---|
| 1830 | var _typeNode as ITypeProxy |
|---|
| 1831 | |
|---|
| 1832 | cue init(typeNode as ITypeProxy) |
|---|
| 1833 | base.init((typeNode to ISyntaxNode).token) # CC: could be potential for making arg a compound interface ISyntaxNode+ITypeProxy from the 'Speculative' list |
|---|
| 1834 | _typeNode = typeNode |
|---|
| 1835 | |
|---|
| 1836 | def isDescendantOf(type as IType) as bool is override |
|---|
| 1837 | assert _representedType |
|---|
| 1838 | return _representedType.isDescendantOf(type) |
|---|
| 1839 | |
|---|
| 1840 | # TODO? |
|---|
| 1841 | # def declForName(name as String) as IBoxMember? is override |
|---|
| 1842 | # assert _representedType |
|---|
| 1843 | # return _representedType.declForName(name) |
|---|
| 1844 | |
|---|
| 1845 | def memberForName(name as String) as IMember? is override |
|---|
| 1846 | assert _representedType |
|---|
| 1847 | return _representedType.memberForName(name) |
|---|
| 1848 | |
|---|
| 1849 | def _bindInt |
|---|
| 1850 | base._bindInt |
|---|
| 1851 | if _representedType is nil |
|---|
| 1852 | _representedType = _typeNode.realType |
|---|
| 1853 | assert _representedType |
|---|
| 1854 | if not _representedType inherits Class and not _representedType inherits Interface |
|---|
| 1855 | .throwError('A generic type constraint must be a class or an interface. "[_representedType.name]" is not.') |
|---|
| 1856 | |
|---|
| 1857 | |
|---|
| 1858 | class Extension inherits Box is partial |
|---|
| 1859 | """ |
|---|
| 1860 | Example: |
|---|
| 1861 | extend String |
|---|
| 1862 | get doubleLength as int |
|---|
| 1863 | return .length * 2 |
|---|
| 1864 | """ |
|---|
| 1865 | |
|---|
| 1866 | var _extendedBoxProxy as ITypeProxy? |
|---|
| 1867 | var _extendedBox as Box? |
|---|
| 1868 | |
|---|
| 1869 | cue init(token as IToken, idToken as IToken, extendedBoxProxy as ITypeProxy, isNames as String*, docString as String?) |
|---|
| 1870 | base.init(token, idToken, '(unnamed extension)', List<of IType>(), isNames, AttributeList(), List<of ITypeProxy>(), docString) |
|---|
| 1871 | _name = '(unnamed extension [.serialNum])' |
|---|
| 1872 | _extendedBoxProxy = extendedBoxProxy |
|---|
| 1873 | |
|---|
| 1874 | cue init(nativeType as NativeType, backend as BackEnd) |
|---|
| 1875 | # this only for Cobra specific extensions. Example: class Extend_String_FileName |
|---|
| 1876 | base.init(TokenFix.empty, TokenFix.empty, backend.cobraNameForNativeBoxName(nativeType.name), List<of IType>(), List<of String>(), AttributeList(), List<of ITypeProxy>(), nil) |
|---|
| 1877 | _initNativeType(nativeType) |
|---|
| 1878 | # the real extended type is not this type, but the type of the first argument of any method |
|---|
| 1879 | nativeType = backend.determineExtnNativeType(this, nativeType) |
|---|
| 1880 | _extendedBoxProxy = backend.nativeTypeProxy(nativeType) |
|---|
| 1881 | (.compiler.curModule to AssemblyModule).addMustBindInh(this) |
|---|
| 1882 | |
|---|
| 1883 | get extendedBox from var |
|---|
| 1884 | |
|---|
| 1885 | get isReference as bool is override |
|---|
| 1886 | return _extendedBox.isReference |
|---|
| 1887 | |
|---|
| 1888 | get englishName as String is override |
|---|
| 1889 | return if(_extendedBox, _extendedBox.englishName+' ', '') + 'extension' |
|---|
| 1890 | |
|---|
| 1891 | def addDecl(decl as IBoxMember) is override |
|---|
| 1892 | base.addDecl(decl) |
|---|
| 1893 | |
|---|
| 1894 | def extensionMemberFor(box as Box, name as String) as IMember? is override |
|---|
| 1895 | # TODO: this method is called too frequently, probably due to _finishOverloads, but may also be other sources. there's no bug, but it may be a performance drag |
|---|
| 1896 | if not .declForName(name), return nil |
|---|
| 1897 | assert .didBindInh |
|---|
| 1898 | .prepIfNeeded |
|---|
| 1899 | assert _extendedBox |
|---|
| 1900 | if _extendedBox |
|---|
| 1901 | if box.isDescendantOf(_extendedBox) |
|---|
| 1902 | return .declForName(name) |
|---|
| 1903 | else if box.isGeneric and .isGeneric |
|---|
| 1904 | # example: |
|---|
| 1905 | # this == Extension(6376, "IEnumerable<of T>.extension.6376") |
|---|
| 1906 | # box == Class(13618, "KeyCollection<of String,int>") |
|---|
| 1907 | # name == 'toList' |
|---|
| 1908 | # cto == Interface(13543, "IEnumerable<of String>") |
|---|
| 1909 | cto = box.constructedTypeOf(_extendedBox.genericDef to !) |
|---|
| 1910 | if cto |
|---|
| 1911 | if box.isDescendantOf(cto) and .declForName(name) |
|---|
| 1912 | return .constructedTypeFor(cto.genericParams).declForName(name) |
|---|
| 1913 | else if .isGeneric |
|---|
| 1914 | # Example: |
|---|
| 1915 | # this == Extension of IEnumerable<of T> |
|---|
| 1916 | # box == X implements IEnumerable<of int> |
|---|
| 1917 | # name == 'toList' |
|---|
| 1918 | # The IEnumerable<of T> has .genericDef IEnumerable<> |
|---|
| 1919 | # The X's IEnumerable<of int> has .genericDef IEnumerable<> |
|---|
| 1920 | # Note that X and the Extension are not directly connected. |
|---|
| 1921 | # Only by tracing up to the generic def IEnumerable<> do they "connect". |
|---|
| 1922 | # see cobra/Tests/420-extensions/400-extend-generics/220-extend-ancestor-interface.cobra |
|---|
| 1923 | constructed = box.constructedTypeOf(_extendedBox.genericDef to !) |
|---|
| 1924 | if constructed, return .extensionMemberFor(constructed, name) |
|---|
| 1925 | return nil |
|---|
| 1926 | |
|---|
| 1927 | def memberForName(name as String) as IMember? |
|---|
| 1928 | result = base.memberForName(name) |
|---|
| 1929 | if result is nil, result = .extendedBox.memberForName(name) |
|---|
| 1930 | return result |
|---|
| 1931 | |
|---|
| 1932 | def symbolForName(name as String, haveThis as bool, firstCall as bool) as IMember? |
|---|
| 1933 | result = base.symbolForName(name, haveThis, firstCall) |
|---|
| 1934 | if result is nil and .extendedBox # may be nil during .bindInh phase |
|---|
| 1935 | result = .extendedBox.symbolForName(name, haveThis, firstCall) |
|---|
| 1936 | return result |
|---|
| 1937 | |
|---|
| 1938 | def _bindInh |
|---|
| 1939 | base._bindInh |
|---|
| 1940 | |
|---|
| 1941 | if _extendedBox is nil |
|---|
| 1942 | if _extendedBoxProxy inherits GenericTypeIdentifier |
|---|
| 1943 | # this will error on the generic params unless we set them up to be found |
|---|
| 1944 | for tn in _extendedBoxProxy.typeNodes |
|---|
| 1945 | if tn inherits TypeIdentifier |
|---|
| 1946 | _genericParams.add(GenericParam(tn.name)) |
|---|
| 1947 | else |
|---|
| 1948 | .throwError('Invalid generic param "[tn]".') |
|---|
| 1949 | |
|---|
| 1950 | realType = _extendedBoxProxy.realType |
|---|
| 1951 | if realType inherits Box |
|---|
| 1952 | _extendedBox = realType |
|---|
| 1953 | if _extendedBox.genericDef |
|---|
| 1954 | _genericParams = List<of IType>(_extendedBox.genericParams) |
|---|
| 1955 | else |
|---|
| 1956 | .throwError('Cannot extend a [realType.name]. You can extend classes, structs and interfaces.') |
|---|
| 1957 | |
|---|
| 1958 | _name = '[_extendedBox.name].extension.[.serialNum]' |
|---|
| 1959 | |
|---|
| 1960 | # shouldn't need or use inherited types |
|---|
| 1961 | _baseClass = nil |
|---|
| 1962 | _baseInterfaceProxies = List<of ITypeProxy>() |
|---|
| 1963 | _baseInterfaces = List<of Interface>() |
|---|
| 1964 | |
|---|
| 1965 | if not _extendedBox.didBindInh, _extendedBox.bindInh |
|---|
| 1966 | |
|---|
| 1967 | def bindInt as INode |
|---|
| 1968 | extendedBox = .extendedBox |
|---|
| 1969 | assert extendedBox.didBindInh |
|---|
| 1970 | if not extendedBox.didBindInt and not extendedBox.isBindingInh, extendedBox.bindInt |
|---|
| 1971 | assert extendedBox.didBindInt |
|---|
| 1972 | return base.bindInt |
|---|
| 1973 | |
|---|
| 1974 | def _bindInt |
|---|
| 1975 | extendedBox = .extendedBox |
|---|
| 1976 | assert extendedBox.didBindInh and extendedBox.didBindInt |
|---|
| 1977 | base._bindInt |
|---|
| 1978 | sharpName = .sharpRef # TODO: how to generalize this beyond CLR? idea: change .sharedMethodBacking to refer to a method instead of being a String |
|---|
| 1979 | for decl in .declsInOrder |
|---|
| 1980 | if decl inherits AbstractMethod |
|---|
| 1981 | if decl inherits Initializer |
|---|
| 1982 | decl.recordError('Extensions can only contain methods, not initializers.') |
|---|
| 1983 | else |
|---|
| 1984 | decl.sharedMethodBacking = '[sharpName].[decl.name.capitalized]' |
|---|
| 1985 | decl.changeToNonVirtual |
|---|
| 1986 | decl.bindInt |
|---|
| 1987 | # handle overloads |
|---|
| 1988 | other = extendedBox.declForName(decl.name) |
|---|
| 1989 | if other |
|---|
| 1990 | newOverload = nil to MemberOverload? |
|---|
| 1991 | if other inherits MemberOverload |
|---|
| 1992 | overload = other |
|---|
| 1993 | else if other inherits AbstractMethod |
|---|
| 1994 | newOverload = overload = MemberOverload(other) |
|---|
| 1995 | extendedBox.registerOverload(overload) |
|---|
| 1996 | else |
|---|
| 1997 | throw FallThroughException([this, decl]) |
|---|
| 1998 | decl.overloadGroup = nil # Could be in a group from the extension itself. And .addMember below doesn't like that. |
|---|
| 1999 | overload.addMember(decl) |
|---|
| 2000 | if newOverload, newOverload.bindInt # an overload that never .bindInt will get cranky later |
|---|
| 2001 | else |
|---|
| 2002 | decl.recordError('Extensions can only contain methods.') |
|---|
| 2003 | |
|---|
| 2004 | def _bindImp |
|---|
| 2005 | base._bindImp |
|---|
| 2006 | for decl in .declsInOrder |
|---|
| 2007 | decl.bindImp |
|---|