SystemOrganization addCategory: #'RoelTyper-Core'! SystemOrganization addCategory: #'RoelTyper-Tests'! InstructionClient subclass: #InstvarInterfaceExtractor instanceVariableNames: 'stack copied initialStack method saveStacks input collector' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !InstvarInterfaceExtractor commentStamp: '' prior: 0! I am responsible for extracting the messages sent to an instance variable and the assignments done to an instance variable. I am supposed to work together with a TypeCollector. Instance Variables: collector description of collector copied description of copied initialStack description of initialStack input description of input method description of method saveStacks description of saveStacks stack <(OrderedCollection of: Object)> description of stack ! !InstvarInterfaceExtractor methodsFor: 'private' stamp: ' 7/9/05 23:28'! copied: list copied := list! ! !InstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! dupFirst stack add: stack last.! ! !InstvarInterfaceExtractor methodsFor: 'extracting' stamp: ' 7/9/05 23:28'! extractInterfacesFrom: m addTo: aTypeCollector method := m. saveStacks := Dictionary new. stack := OrderedCollection new. method numTemps timesRepeat: [stack add: #temp]. initialStack := stack copy. collector := aTypeCollector. input := InstructionStream on: method. [input atEnd] whileFalse: [self reloadStack. input interpretNextInstructionFor: self]! ! !InstvarInterfaceExtractor methodsFor: 'private' stamp: ' 7/9/05 23:28'! input ^input! ! !InstvarInterfaceExtractor methodsFor: 'private' stamp: ' 7/9/05 23:28'! method: aMethod method := aMethod. copied := #()! ! !InstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! pop stack removeLast.! ! !InstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! pushConstant: value value class == BlockClosure ifTrue: [self readBlock: value method copied: 0] ifFalse: [stack addLast: value class]! ! !InstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! pushContext stack add: #context.! ! !InstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! pushInst: index stack add: index! ! !InstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! pushReceiver stack addLast: #self.! ! !InstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! pushStatic: assoc "assoc can be an association OR a variable binding. I just push the complete association, since it does not interest me for the moment." stack addLast: assoc! ! !InstvarInterfaceExtractor methodsFor: 'private' stamp: ' 7/9/05 23:28'! readBlock: block copied: count | newCopied | newCopied := stack removeLast: count. stack add: #block. ^self class new copied: newCopied; extractInterfacesFrom: block addTo: collector! ! !InstvarInterfaceExtractor methodsFor: 'private' stamp: ' 7/9/05 23:28'! reloadStack stack isNil ifTrue: [stack := self saveStacks at: self input pc ifAbsent: [initialStack copy]. ^self]. stack := self saveStacks at: self input pc ifAbsent: [stack]! ! !InstvarInterfaceExtractor methodsFor: 'private' stamp: ' 7/9/05 23:28'! saveStacks saveStacks ifNil: [saveStacks := Dictionary new]. ^saveStacks! ! !InstvarInterfaceExtractor methodsFor: 'opcodes-control' stamp: ' 7/9/05 23:28'! send: selector numArgs: na | receiver args | args := stack removeLast: na. receiver := (stack removeLast: 1) first. receiver isInteger ifTrue: [collector addSend: selector to: receiver]. stack add: (collector pushSendOf: selector to: receiver args: args)! ! InstvarInterfaceExtractor subclass: #SqueakInstvarInterfaceExtractor instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! blockReturnTop "Return Top Of Stack bytecode." ^self pop! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! doDup "Duplicate Top Of Stack bytecode." self dupFirst! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! doPop "Remove Top Of Stack bytecode." ^self pop! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! jump: delta | currentPC | currentPC := self input pc. delta > 0 ifTrue: [self saveStacks at: currentPC+delta put: stack copy. stack := OrderedCollection new].! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! jump: delta if: condition self pop. "receiver of ifTrue or ifFalse, according to condition" delta > 0 ifTrue: [self saveStacks at: self input pc+delta put: (stack copy add: #computed; yourself)].! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! methodReturnConstant: value "Return Constant bytecode." ^self pushConstant: value; sqReturnTop! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! methodReturnReceiver "Return Self bytecode." ^self pushReceiver; sqReturnTop! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! methodReturnTop "Return Top Of Stack bytecode." ^self sqReturnTop! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! popIntoLiteralVariable: anAssociation "Remove Top Of Stack And Store Into Literal Variable bytecode." ^self pop! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! popIntoReceiverVariable: offset "Remove Top Of Stack And Store Into Instance Variable bytecode." collector handleAssignment: stack removeLast for: offset! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! popIntoTemporaryVariable: offset "Remove Top Of Stack And Store Into Temporary Variable bytecode." "Nothing to do,since I do not treat temporary variables for the moment."! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! pushActiveContext "Push Active Context On Top Of Its Own Stack bytecode." self pushContext! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! pushLiteralVariable: anAssociation "Push Contents Of anAssociation On Top Of Stack bytecode." self pushStatic: anAssociation! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! pushReceiverVariable: offset "Push Contents Of the Receiver's Instance Variable Whose Index is the argument, offset, On Top Of Stack bytecode." self pushInst: offset! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! pushTemporaryVariable: offset "Push Contents Of Temporary Variable Whose Index Is the argument, offset, On Top Of Stack bytecode." stack add: #tempVariable! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! send: selector super: supered numArgs: numberArguments "Send Message With Selector, selector, bytecode. The argument, supered, indicates whether the receiver of the message is specified with 'super' in the source method. The arguments of the message are found in the top numArguments locations on the stack and the receiver just below them." ^supered ifTrue: [self sendSuper: selector numArgs: numberArguments] ifFalse: [self send: selector numArgs: numberArguments]! ! !SqueakInstvarInterfaceExtractor methodsFor: 'opcodes-control' stamp: ' 7/9/05 23:28'! sendSuper: selector numArgs: na stack removeLast: na + 1. stack add: #computed! ! !SqueakInstvarInterfaceExtractor methodsFor: 'private' stamp: ' 7/9/05 23:28'! sqReturnTop "In VW, method returnTop is inherited from instructionClient and does nothing."! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! storeIntoLiteralVariable: anAssociation "Store Top Of Stack Into Literal Variable Of Method bytecode." "Nothing to do, since I do not do anything with literal variables. Just keep the right-hand side on the stack for further processing"! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! storeIntoReceiverVariable: offset "Store Top Of Stack Into Instance Variable Of Method bytecode." | rvalue | collector handleAssignment: (rvalue := stack removeLast) for: offset. stack add: rvalue! ! !SqueakInstvarInterfaceExtractor methodsFor: 'instruction decoding' stamp: ' 7/9/05 23:28'! storeIntoTemporaryVariable: offset "Store Top Of Stack Into Temporary Variable Of Method bytecode." "Nothing to do,since I do not treat temporary variables for the moment."! ! InstvarInterfaceExtractor subclass: #VWInstvarInterfaceExtractor instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! dupLast stack removeLast.! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! dupNext stack removeLast; add: stack last.! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-control' stamp: ' 7/9/05 23:28'! jump: delta | currentPC | currentPC := self input pc. delta > 0 ifTrue: [self saveStacks at: currentPC+delta put: (self saveStacks at:currentPC). self saveStacks removeKey: currentPC].! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-control' stamp: ' 7/9/05 23:28'! jump: delta if: condition self pop. "receiver of ifTrue or ifFalse, according to condition" delta > 0 ifTrue: [self saveStacks at: self input pc+delta put: (stack copy add: #computed; yourself)].! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-control' stamp: ' 7/9/05 23:28'! makeCopyingBlock: meth count: count self readBlock: meth copied: count! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-control' stamp: ' 7/9/05 23:28'! makeFullBlock: meth self readBlock: meth copied: 0! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-control' stamp: ' 7/9/05 23:28'! makeFullCopyingBlock: meth count: count self readBlock: meth copied: count! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-control' stamp: ' 7/9/05 23:28'! methodPrimitive: index stack add: #errorCode.! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! pushCopiedValues: count copied size = count ifFalse: [self error: (#copiedMismatch << #dialogs >> 'copied mismatch')]. stack addAll: copied. initialStack addAll: copied! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! pushLocal: index stack add: (stack at: index+1).! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! pushLocalIndirect: majorIndex index: minorIndex stack add: ((stack at: majorIndex + 1) == #self ifTrue: [minorIndex] ifFalse: [#thing])! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! pushNewArray: size stack add: #array.! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-control' stamp: ' 7/9/05 23:28'! sendNoCheck: selector numArgs: na self send: selector numArgs: na! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-control' stamp: ' 7/9/05 23:28'! sendNonImmediate: selector numArgs: na self send: selector numArgs: na! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-control' stamp: ' 7/9/05 23:28'! sendSuper: selector numArgs: na stack removeLast: na + 2. stack add: #computed! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! storePopInst: index collector handleAssignment: stack removeLast for: index! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! storePopLocal: index stack size = method numArgs ifTrue: [method primitiveNumber ifNil: [self error: (#BadMethod << #dialogs >> 'bad method')]] ifFalse: [self pop].! ! !VWInstvarInterfaceExtractor methodsFor: 'opcodes-data movement' stamp: ' 7/9/05 23:28'! storePopLocalIndirect: majorIndex index: minorIndex "Need to have a look at this, since an instance variable is being used (so I'd like to push its index on to the stack) bu I don't really know how. " self pop. " (stack at: majorIndex+1) == #self ifTrue: [instvarsInterface add: minorIndex]"! ! Object subclass: #AbstractType instanceVariableNames: 'ivarClass ivarName' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !AbstractType class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! forInstvar: iv inClass: aClass ^(self basicNew) initialize ivarName: iv; ivarClass: aClass; yourself! ! !AbstractType class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! new ^self shouldNotImplement! ! !AbstractType methodsFor: 'private' stamp: ' 7/9/05 23:28'! conflictingAssignmentsWith: anExtractedType | conflictingAssignments | conflictingAssignments := anExtractedType assignments select: [:assignment | (self types includes: assignment) not]. ^conflictingAssignments! ! !AbstractType methodsFor: 'private' stamp: ' 7/9/05 23:28'! conflictingSelectorsWith: anExtractedType | conflictingSelectors | conflictingSelectors := Dictionary new. anExtractedType interface do: [:selector | self types do: [:aType | (aType canUnderstand: selector) ifFalse: [(conflictingSelectors at: selector ifAbsentPut: [OrderedCollection new]) add: aType]]]. ^conflictingSelectors! ! !AbstractType methodsFor: 'comparing' stamp: ' 7/9/05 23:28'! conformsTo: anExtractedType "I am a type. Return whether my types conform to the interface and assignments from the argument." | conflictingSelectors conflictingAssignments | conflictingSelectors := self conflictingSelectorsWith: anExtractedType. conflictingAssignments := self conflictingAssignmentsWith: anExtractedType. ^(conflictingSelectors isEmpty and: [conflictingAssignments isEmpty]) ifTrue: [NoTypingConflict existingResult: self newResult: anExtractedType] ifFalse: [TypingConflict existingResult: self newResult: anExtractedType conflictingSelectors: conflictingSelectors conflictingAssignments: conflictingAssignments]! ! !AbstractType methodsFor: 'initialize-release' stamp: ' 7/9/05 23:28'! initialize "Do nothing, but give subclasses the chance to override."! ! !AbstractType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! is: aClass ^self isSingularType and: [self types first = aClass]! ! !AbstractType methodsFor: 'comparing' stamp: ' 7/9/05 23:28'! isConformingTo: aType ^(self conformsTo: aType) notConflict! ! !AbstractType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! isEditedResult ^self subclassResponsibility! ! !AbstractType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! isExtractedResult ^self subclassResponsibility! ! !AbstractType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! isObjectType ^self isSingularType and: [self types includes: Object]! ! !AbstractType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! isSingularType ^self types size = 1! ! !AbstractType methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! ivarClass ^ivarClass! ! !AbstractType methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! ivarClass: aClass ivarClass := aClass. self triggerEvent: #changed! ! !AbstractType methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! ivarName ^ivarName! ! !AbstractType methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! ivarName: aSymbol ivarName := aSymbol. self triggerEvent: #changed! ! !AbstractType methodsFor: 'printing' stamp: ' 7/9/05 23:28'! printOn: aStream self printTypesOn: aStream! ! !AbstractType methodsFor: 'printing' stamp: ' 7/9/05 23:28'! printTypesOn: aStream self types do: [:each | aStream print: each] separatedBy: [aStream nextPutAll: ' , ']! ! !AbstractType methodsFor: 'comparing' stamp: ' 7/9/05 23:28'! sameAs: aTypingResult "Return whether the receiver and the arguments are the same e.g. whether they have the same values for the interfaces, sends and extracted types." ^self subclassResponsibility! ! !AbstractType methodsFor: 'comparing-private' stamp: ' 7/9/05 23:28'! sameAsEditedType: anEditedTypingResult "Return whether the receiver and the arguments are the same e.g. whether they have the same values for the interfaces, sends and extracted types." ^self subclassResponsibility! ! !AbstractType methodsFor: 'comparing-private' stamp: ' 7/9/05 23:28'! sameAsExtractedType: anExtractedTypingResult "Return whether the receiver and the arguments are the same e.g. whether they have the same values for the interfaces, sends and extracted types." ^self subclassResponsibility! ! !AbstractType methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! types ^self subclassResponsibility! ! AbstractType subclass: #EditedType instanceVariableNames: 'editedTypes' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !EditedType commentStamp: '' prior: 0! I represent a TypingResult in which the user has made changes.! !EditedType class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! forInstvar: iv inClass: aClass types: aClassCollection ^(self forInstvar: iv inClass: aClass) editedTypes: aClassCollection! ! !EditedType methodsFor: 'private-accessing' stamp: ' 7/9/05 23:28'! editedTypes: aCollection editedTypes := aCollection. self triggerEvent: #changed! ! !EditedType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! isEditedResult ^true! ! !EditedType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! isExtractedResult ^false! ! !EditedType methodsFor: 'printing' stamp: ' 7/9/05 23:28'! printOn: aStream aStream nextPutAll: 'EditedType: '. self printTypesOn: aStream! ! !EditedType methodsFor: 'comparing' stamp: ' 7/9/05 23:28'! sameAs: aTypingResult "Return whether the receiver and the arguments are the same e.g. whether they have the same values for the interfaces, sends and extracted types." ^aTypingResult sameAsEditedType: self! ! !EditedType methodsFor: 'comparing-private' stamp: ' 7/9/05 23:28'! sameAsEditedType: anEditedTypingResult "Return whether the receiver and the arguments are the same e.g. whether they have the same values for the interfaces, sends and extracted types." ^self types sameElements: anEditedTypingResult types! ! !EditedType methodsFor: 'comparing-private' stamp: ' 7/9/05 23:28'! sameAsExtractedType: anExtractedTypingResult "Return whether the receiver and the arguments are the same e.g. whether they have the same values for the interfaces, sends and extracted types." ^self types sameElements: anExtractedTypingResult types! ! !EditedType methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! types ^editedTypes! ! AbstractType subclass: #ExtractedType instanceVariableNames: 'interface assignments extractedTypes' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !ExtractedType class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! forInstvar: iv inClass: aClass interface: selectorCollection assignments: classCollection ^(self forInstvar: iv inClass: aClass) interface: selectorCollection assignments: classCollection! ! !ExtractedType methodsFor: 'private-accessing' stamp: ' 7/9/05 23:28'! addAssignment: anObject (self assignments includes: anObject) ifFalse: [self assignments add: anObject]! ! !ExtractedType methodsFor: 'private-accessing' stamp: ' 7/9/05 23:28'! addSend: anObject self interface add: anObject! ! !ExtractedType methodsFor: 'private-accessing' stamp: ' 7/9/05 23:28'! assignments ^assignments! ! !ExtractedType methodsFor: 'private-accessing' stamp: ' 7/9/05 23:28'! basicExtractedTypes ^extractedTypes! ! !ExtractedType methodsFor: 'private' stamp: ' 7/9/05 23:28'! cleanedAssignments | assigns | assigns := self assignments copy. ((assigns includes: True) and: [assigns includes: False]) ifTrue: [assigns remove: True; remove: False; add: Boolean]. ^assigns! ! !ExtractedType methodsFor: 'private' stamp: ' 7/9/05 23:28'! fold: interfaceClasses with: assignmentClasses | commonSuper | interfaceClasses remove: Object ifAbsent: []. "breaks constraint that all classes found are most abstract useful types!!" assignmentClasses do: [:each | commonSuper := interfaceClasses detect: [:sendResultClass | each includesBehavior: sendResultClass] ifNone: [nil]. commonSuper ifNotNil: [interfaceClasses remove: commonSuper; add: each ] ifNil: [ interfaceClasses copy detect: [:cl | cl includesBehavior: each] ifNone: [interfaceClasses add: each]]. ]. interfaceClasses isEmpty ifTrue: [interfaceClasses add: Object]. "Add again if nothing found" ^interfaceClasses asSortedCollection: [:cl1 :cl2 | cl1 name < cl2 name].! ! !ExtractedType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! hasEmptyAssignments ^self assignments isEmpty! ! !ExtractedType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! hasEmptyInterface ^self interface isEmpty! ! !ExtractedType methodsFor: 'initialize-release' stamp: ' 7/9/05 23:28'! initialize super initialize. self interface: IdentitySet new assignments: OrderedCollection new! ! !ExtractedType methodsFor: 'private-accessing' stamp: ' 7/9/05 23:28'! interface ^interface! ! !ExtractedType methodsFor: 'private-accessing' stamp: ' 7/9/05 23:28'! interface: selectorCollection assignments: classCollection interface := selectorCollection. assignments := classCollection! ! !ExtractedType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! isEditedResult ^false! ! !ExtractedType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! isEmpty ^self hasEmptyAssignments and: [self hasEmptyInterface]! ! !ExtractedType methodsFor: 'testing' stamp: ' 7/9/05 23:28'! isExtractedResult ^true! ! !ExtractedType methodsFor: 'printing' stamp: ' 7/9/05 23:28'! printInterfaceAndAssigmentsOn: aStream aStream nextPutAll: 'Sends: {'. self interface do: [:symbol | aStream print: symbol] separatedBy: [aStream space]. aStream nextPutAll: '}'; cr; nextPutAll: 'Assignments: {'. self assignments do: [:symbol | aStream print: symbol] separatedBy: [aStream space]. aStream nextPutAll: '}'; cr! ! !ExtractedType methodsFor: 'printing' stamp: ' 7/9/05 23:28'! printOn: aStream aStream nextPutAll: 'ExtractedType: '. self basicExtractedTypes ifNil: [self printInterfaceAndAssigmentsOn: aStream] ifNotNil: [self printTypesOn: aStream]! ! !ExtractedType methodsFor: 'private' stamp: ' 7/9/05 23:28'! rootsUnderstanding: selectors | initialClasses nextClasses traverseClassesStack next prototypeSet | prototypeSet := IdentitySet new: 20. nextClasses := prototypeSet copy add: Object; yourself. selectors do: [:selector | initialClasses := nextClasses. nextClasses := prototypeSet copy. initialClasses do: [:initialClass | (initialClass canUnderstand: selector) ifTrue: [nextClasses add: initialClass] ifFalse: [traverseClassesStack := OrderedCollection with: initialClass. [traverseClassesStack isEmpty] whileFalse: [next := traverseClassesStack removeFirst. next nonMetaSubclassesDo: [:subcl | (subcl includesSelector: selector) ifTrue: [nextClasses add: subcl] ifFalse: [traverseClassesStack add: subcl]]]]]]. ^nextClasses! ! !ExtractedType methodsFor: 'comparing' stamp: ' 7/9/05 23:28'! sameAs: aTypingResult "Return whether the receiver and the arguments are the same e.g. whether they have the same values for the interfaces, sends and extracted types." ^aTypingResult sameAsExtractedType: self! ! !ExtractedType methodsFor: 'comparing-private' stamp: ' 7/9/05 23:28'! sameAsEditedType: anEditedTypingResult "Return whether the receiver and the arguments are the same e.g. whether they have the same values for the interfaces, sends and extracted types." ^self types sameElements: anEditedTypingResult types! ! !ExtractedType methodsFor: 'comparing-private' stamp: ' 7/9/05 23:28'! sameAsExtractedType: anExtractedTypingResult "Return whether the receiver and the arguments are the same e.g. whether they have the same values for the interfaces, sends and extracted types." ^(self assignments sameElements: anExtractedTypingResult assignments) and: [ (self interface sameElements: anExtractedTypingResult interface) and: [ (self basicExtractedTypes isNil and: [anExtractedTypingResult basicExtractedTypes isNil]) or: [self types sameElements: anExtractedTypingResult types]]]! ! !ExtractedType methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! types ^extractedTypes ifNil: [extractedTypes := self fold: (self rootsUnderstanding: self interface) with: self cleanedAssignments] ifNotNil: [extractedTypes]! ! Object subclass: #AbstractTypeComparison instanceVariableNames: 'newResult existingResult' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !AbstractTypeComparison class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! existingResult: existingTypingResult newResult: newTypingResult ^self basicNew newResult: newTypingResult; existingResult: existingTypingResult; yourself! ! !AbstractTypeComparison class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! new ^self shouldNotImplement! ! !AbstractTypeComparison methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! existingResult ^existingResult! ! !AbstractTypeComparison methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! existingResult: anObject existingResult := anObject! ! !AbstractTypeComparison methodsFor: 'printing' stamp: ' 7/9/05 23:28'! explanationString ^self subclassResponsibility! ! !AbstractTypeComparison methodsFor: 'testing' stamp: ' 7/9/05 23:28'! isConflict ^false! ! !AbstractTypeComparison methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! ivarClass ^self newResult ivarClass! ! !AbstractTypeComparison methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! ivarName ^self newResult ivarName! ! !AbstractTypeComparison methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! newResult ^newResult! ! !AbstractTypeComparison methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! newResult: anObject newResult := anObject! ! !AbstractTypeComparison methodsFor: 'testing' stamp: ' 7/9/05 23:28'! notConflict ^self isConflict not! ! AbstractTypeComparison subclass: #NoTypingConflict instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !NoTypingConflict methodsFor: 'printing' stamp: ' 7/9/05 23:28'! explanationString ^'No conflict.'! ! !NoTypingConflict methodsFor: 'printing' stamp: ' 7/9/05 23:28'! printOn: aStream aStream nextPutAll: 'Type OK for '; nextPutAll: self ivarClass shortName; nextPutAll: ' - '; nextPutAll: self ivarName! ! AbstractTypeComparison subclass: #TypingConflict instanceVariableNames: 'conflictingSelectors conflictingAssignments' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !TypingConflict class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! existingResult: existingTypingResult newResult: newTypingResult conflictingSelectors: selectorsCollection conflictingAssignments: classCollection ^(self existingResult: existingTypingResult newResult: newTypingResult) conflictingSelectors: selectorsCollection conflictingAssignments: classCollection! ! !TypingConflict methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! conflictingAssignments ^conflictingAssignments! ! !TypingConflict methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! conflictingSelectors ^conflictingSelectors! ! !TypingConflict methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! conflictingSelectors: selectorsCollection conflictingAssignments: classCollection conflictingSelectors := selectorsCollection. conflictingAssignments := classCollection! ! !TypingConflict methodsFor: 'printing' stamp: ' 7/9/05 23:28'! explanationString | str | str := WriteStream on: String new. self printSelectorsNotUnderstoodOn: str. self printAssignmentConflictsOn: str. ^str contents! ! !TypingConflict methodsFor: 'testing' stamp: ' 7/9/05 23:28'! isConflict ^true! ! !TypingConflict methodsFor: 'printing' stamp: ' 7/9/05 23:28'! printAssignmentConflictsOn: str self conflictingAssignments isEmpty ifFalse: [str nextPutAll: 'There are conflicts between assignments.']! ! !TypingConflict methodsFor: 'printing' stamp: ' 7/9/05 23:28'! printOn: aStream aStream nextPutAll: 'Type conflict for '; nextPutAll: self ivarClass shortName; nextPutAll: ' - '; nextPutAll: self ivarName! ! !TypingConflict methodsFor: 'printing' stamp: ' 7/9/05 23:28'! printSelectorsNotUnderstoodOn: str str nextPutAll: 'Following selector problems were found:'; crtab. self conflictingSelectors associations do: [:assoc | str print: assoc key; nextPutAll: ' not understood by: {'. assoc value do: [:cl | str print: cl] separatedBy: [str nextPut: $,]. str nextPut: $} ] separatedBy: [str nextPut: $,; crtab]. " | selectorsNotUnderstood | selectorsNotUnderstood := self conflictingSelectors keys. selectorsNotUnderstood isEmpty ifFalse: [str nextPutAll: 'Following selectors are not understood by existing type: '. selectorsNotUnderstood do: [:sel | str print: sel] separatedBy: [str nextPut: $,]. str nextPut: $.; cr]"! ! Object subclass: #TypeCollector instanceVariableNames: 'theClass instVars typingResults' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !TypeCollector commentStamp: '' prior: 0! I collect and assemble the types sent to instance variables for a certain class (I use the InterfaceExtractor for that), And use them to create and return TypingResults. Instance Variables: assignments description of assignments instVarOffset description of instVarOffset instVars <(Palette of: (ExceptionSet | GenericException | SequenceableCollection | Signal)) | (SequenceableCollection of: (ExceptionSet | GenericException | SequenceableCollection | Signal))> description of instVars sends description of sends theClass description of theClass ! TypeCollector subclass: #SqueakTypeCollector instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !SqueakTypeCollector methodsFor: 'heuristics' stamp: ' 7/9/05 23:28'! assignmentTypeOf: val val isBehavior ifTrue: [^val]. val isVariableBinding ifTrue: [ (val key == #instcreation) ifTrue: [^val value] ifFalse: [^val value class]]. ^nil! ! !SqueakTypeCollector methodsFor: 'heuristics' stamp: ' 7/9/05 23:28'! langueSpecificPushSendOf: selector to: rec args: args (selector == #blockCopy:) ifTrue: [^#block]. (#(#// #quo: #rem: #\\ #ceiling #floor #rounded #roundTo: #truncated #truncateTo: #/ #+ #- #* #abs #negated #reciprocal) includes: selector) ifTrue: [^Number]. ^#computed! ! !SqueakTypeCollector methodsFor: 'private' stamp: ' 7/9/05 23:28'! newExtractor ^SqueakInstvarInterfaceExtractor new! ! !TypeCollector class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! new "Override new to return either a VWTypeCollector or a SqueakTypeCollector" ^self newForPlatform! ! !TypeCollector class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! newForPlatform "Return either a VWTypeCollector or a SqueakTypeCollector, depending on the platform used." | versionString | versionString := Smalltalk version. ('*Squeak*' match: versionString) ifTrue: [^SqueakTypeCollector basicNew]. ('*VisualWorks*' match: versionString) ifTrue: [^VWTypeCollector basicNew]. ^self error: 'Unsupported Platform!!'! ! !TypeCollector class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! onClass: aClass ^self new onClass: aClass! ! !TypeCollector class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! typeInstvarsOfClass: aClass ^self new typeInstvarsOfClass: aClass! ! !TypeCollector methodsFor: 'adding' stamp: ' 7/9/05 23:28'! addAssignment: value to: index self withTranslatedIndex: index do: [:i | (self typingResults at: i) addAssignment: value]! ! !TypeCollector methodsFor: 'adding' stamp: ' 7/9/05 23:28'! addSend: selector to: index "Add a range check to filter out sends to instvars defined in superclasses, etc." self withTranslatedIndex: index do: [:i | (self typingResults at: i) addSend: selector]! ! !TypeCollector methodsFor: 'heuristics' stamp: ' 7/9/05 23:28'! assignmentTypeOf: val ^self subclassResponsibility! ! !TypeCollector methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! assignmentsTo: instVarName ^(self typingResultsFor: instVarName) assignments! ! !TypeCollector methodsFor: 'heuristics' stamp: ' 7/9/05 23:28'! handleAssignment: val for: index "Cannot use ifNotNil: with argument in Squeak, so use a temporary instead." | result | result := nil. val isInteger ifTrue: [self withTranslatedIndex: val do: [:idx | result := self lastAssignmentForIndex: idx]] ifFalse: [result := self assignmentTypeOf: val]. result ifNotNil: [self addAssignment: result to: index]! ! !TypeCollector methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! indexForVar: iVar "Note: works for Squeak and VisualWorks. If it would be only for VW, you could just use instVarIndexFor: instead." ^instVars indexOf: iVar! ! !TypeCollector methodsFor: 'heuristics' stamp: ' 7/9/05 23:28'! langueSpecificPushSendOf: selector to: rec args: args ^#computed! ! !TypeCollector methodsFor: 'private' stamp: ' 7/9/05 23:28'! lastAssignmentForIndex: anIndex | assignments | assignments := (self typingResults at: anIndex) assignments. ^assignments isEmpty ifTrue: [nil] ifFalse: [assignments last]! ! !TypeCollector methodsFor: 'private' stamp: ' 7/9/05 23:28'! newExtractor "Return a new extractor class. This is typically Smalltalk dialect dependent, so subclasses have to override to choose the one they want." ^self subclassResponsibility! ! !TypeCollector methodsFor: 'initialize-release' stamp: ' 7/9/05 23:28'! onClass: aClass theClass := aClass. instVars := aClass allInstVarNames collect: [:e | e asSymbol]. typingResults := (instVars collect: [:ivar | ExtractedType forInstvar: ivar inClass: aClass]) asArray.! ! !TypeCollector methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! packagedResults | results | results := IdentityDictionary new: self typingResults size. instVars size - theClass instVarNames size + 1 to: instVars size do: [:index | results at: (instVars at: index) put: (self typingResults at: index)]. ^results! ! !TypeCollector methodsFor: 'heuristics' stamp: ' 7/9/05 23:28'! pushSendOf: selector to: rec args: args "Needs to be optimized" | recValue index | (rec == #self) ifTrue: [ ((index := instVars indexOf: selector) > 0) ifTrue: [^index - 1]. ((selector last == $:) and: [(index := instVars indexOf: (selector copyFrom: 1 to: selector size - 1) asSymbol) > 0]) ifTrue: [self handleAssignment: args first for: index - 1. ^#computed]]. (#(#= #== #< #> #<= #>= #~=) includes: selector) ifTrue: [^Boolean]. ('is*' match: selector) ifTrue: [^Boolean]. ((rec isVariableBinding) and: [(recValue := rec value) isBehavior and: [(recValue class categoryForSelector: selector) == #'instance creation' ]]) ifTrue: [^Association key: #instcreation value: recValue]. ^self langueSpecificPushSendOf: selector to: rec args: args! ! !TypeCollector methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! sendsTo: instVarName " ^self sends at: (self indexForVar: instVarName)" ^(self typingResultsFor: instVarName) interface! ! !TypeCollector methodsFor: 'public-typing' stamp: ' 7/9/05 23:28'! typeInstvarsOfClass: aClass | extractor | self onClass: aClass. extractor := self newExtractor. aClass selectorsAndMethodsDo: [:sel :method | extractor extractInterfacesFrom: method addTo: self]. ^self packagedResults! ! !TypeCollector methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! typingResults ^typingResults! ! !TypeCollector methodsFor: 'private' stamp: ' 7/9/05 23:28'! typingResultsFor: instVarName ^self typingResults at: (self indexForVar: instVarName)! ! !TypeCollector methodsFor: 'private' stamp: ' 7/9/05 23:28'! withTranslatedIndex: index do: aBlock aBlock value: index + 1! ! TypeCollector subclass: #VWTypeCollector instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !VWTypeCollector methodsFor: 'heuristics' stamp: ' 7/9/05 23:28'! assignmentTypeOf: val val isBehavior ifTrue: [^val]. val isVariableBinding ifTrue: [^val value class]. (val isKindOf: Association) ifTrue: [^val value]. ^nil! ! !VWTypeCollector methodsFor: 'heuristics' stamp: ' 7/9/05 23:28'! langueSpecificPushSendOf: selector to: rec args: args "Needs to optimized, but since I need to go I'll publish it like this for the moment" (#(#/ #+ #- #* #abs #negated #reciprocal) includes: selector) ifTrue: [^ArithmeticValue]. (#(#// #quo: #rem: #\\ #ceiling #floor #rounded #roundTo: #truncated #truncateTo:) includes: selector) ifTrue: [^Number]. ^#computed! ! !VWTypeCollector methodsFor: 'private' stamp: ' 7/9/05 23:28'! newExtractor ^VWInstvarInterfaceExtractor new! ! Object subclass: #TypingResultKeeper instanceVariableNames: 'timeTaken typeResults' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Core'! !TypingResultKeeper class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! forImage ^self new forImage! ! !TypingResultKeeper class methodsFor: 'instance creation' stamp: ' 7/9/05 23:28'! new ^super new initialize! ! !TypingResultKeeper methodsFor: 'private' stamp: ' 7/9/05 23:28'! addCollectorResult: collectorResult collectorResult isEmpty ifTrue: [^self]. typeResults at: collectorResult values first ivarClass put: collectorResult! ! !TypingResultKeeper methodsFor: 'private' stamp: ' 7/9/05 23:28'! addTypingResult: aTypeResult | typeResultsForClass | typeResultsForClass := self typeResults at: aTypeResult ivarClass ifAbsentPut: [Dictionary new]. typeResultsForClass at: aTypeResult ivarName put: aTypeResult! ! !TypingResultKeeper methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! calculateTypesForClass: aClass ^TypeCollector typeInstvarsOfClass: aClass! ! !TypingResultKeeper methodsFor: 'public' stamp: ' 7/9/05 23:28'! forImage | collector | collector := TypeCollector new. timeTaken := Time millisecondsToRun: [Object allSubclasses do: [:cl | cl isMeta ifFalse: [ self addCollectorResult: ( collector typeInstvarsOfClass: cl)]]]! ! !TypingResultKeeper methodsFor: 'initialize-release' stamp: ' 7/9/05 23:28'! initialize typeResults := IdentityDictionary new! ! !TypingResultKeeper methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! nrObjectTypes | nr | nr := 0. self withAllInstvarResultsDo: [:cl :ivar :typeResult | (typeResult is: Object) ifTrue: [nr := nr + 1]]. ^nr! ! !TypingResultKeeper methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! nrUniqueTypes | nr | nr := 0. self withAllInstvarResultsDo: [:cl :ivar :typeResult | typeResult isSingularType ifTrue: [nr := nr + 1]]. ^nr! ! !TypingResultKeeper methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! resetTypesForClass: aClass ^typeResults removeKey: aClass ifAbsent: []! ! !TypingResultKeeper methodsFor: 'private' stamp: ' 7/9/05 23:28'! resultsForClass: aClass instvar: instvar ifAbsent: absentBlock | ivars | ivars := typeResults at: aClass ifAbsent: absentBlock. ^ivars at: instvar ifAbsent: absentBlock! ! !TypingResultKeeper methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! timeTaken ^timeTaken! ! !TypingResultKeeper methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! typeResults ^typeResults! ! !TypingResultKeeper methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! typesForClass: aClass ^typeResults at: aClass ifAbsentPut: [self calculateTypesForClass: aClass]! ! !TypingResultKeeper methodsFor: 'accessing' stamp: ' 7/9/05 23:28'! typesForClass: aClass instvar: instvar ^(self typesForClass: aClass) at: instvar ifAbsent: [ExtractedType forInstvar: instvar inClass: aClass]! ! !TypingResultKeeper methodsFor: 'enumerating' stamp: ' 7/9/05 23:28'! withAllInstvarResultsDo: aBlock self typeResults keysAndValuesDo: [:cl :instvarDict | instvarDict keysAndValuesDo: [:ivar :typeResult | aBlock value: cl value: ivar value: typeResult]]! ! TestCase subclass: #RoelTypingTestRoot instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Tests'! RoelTypingTestRoot subclass: #InstvarInterfaceExtractorTest instanceVariableNames: 'a b c u v w x y z' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Tests'! !InstvarInterfaceExtractorTest methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! assertAssignments: description in: collector | emptyIndexes ivarName ivarInterface extractedInterface ivarIndex anArray | anArray := collector typingResults. emptyIndexes := (1 to: self class instVarNames size) asOrderedCollection. description do: [:desc | ivarName := desc first. ivarInterface := desc at: 2. ivarIndex := collector indexForVar: ivarName. extractedInterface := collector assignmentsTo: ivarName. self assert: extractedInterface size = ivarInterface size. self assert: (extractedInterface allSatisfy: [:each | ivarInterface includes: each name]). emptyIndexes remove: ivarIndex]. self emptyAssigment: anArray atIndexes: emptyIndexes.! ! !InstvarInterfaceExtractorTest methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! assertSends: description in: collector | emptyIndexes ivarName ivarInterface extractedInterface ivarIndex anArray | anArray := collector typingResults. emptyIndexes := (1 to: self class instVarNames size) asOrderedCollection. description do: [:desc | ivarName := desc first. ivarInterface := desc at: 2. ivarIndex := collector indexForVar: ivarName. extractedInterface := collector sendsTo: ivarName. self assert: extractedInterface size = ivarInterface size. self assert: (extractedInterface allSatisfy: [:each | ivarInterface includes: each]). emptyIndexes remove: ivarIndex]. self emptyInterface: anArray atIndexes: emptyIndexes.! ! !InstvarInterfaceExtractorTest methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! denyAssignments: description in: collector | emptyIndexes ivarName ivarInterface extractedInterface ivarIndex anArray | anArray := collector typingResults. emptyIndexes := (1 to: self class instVarNames size) asOrderedCollection. description do: [:desc | ivarName := desc first. ivarInterface := desc at: 2. ivarIndex := collector indexForVar: ivarName. extractedInterface := collector assignmentsTo: ivarName. ivarInterface do: [:each | self deny: (extractedInterface includes: each)]. emptyIndexes remove: ivarIndex]. self emptyAssigment: anArray atIndexes: emptyIndexes.! ! !InstvarInterfaceExtractorTest methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! empty: anArray atIndexes: indexCollection indexCollection do: [:index | self assert: (anArray at: index) isEmpty]! ! !InstvarInterfaceExtractorTest methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! emptyAssigment: anArray atIndexes: indexCollection indexCollection do: [:index | self assert: (anArray at: index) hasEmptyAssignments]! ! !InstvarInterfaceExtractorTest methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! emptyInterface: anArray atIndexes: indexCollection indexCollection do: [:index | self assert: (anArray at: index) hasEmptyInterface]! ! !InstvarInterfaceExtractorTest methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! processMethod: aCompiledMethod "Fail by default. Needs to be overridden by subclasses to trigger the base testing backbone." | collector | collector := TypeCollector onClass: self class. TypeCollector new newExtractor extractInterfacesFrom: aCompiledMethod addTo: collector. ^collector! ! !InstvarInterfaceExtractorTest methodsFor: 'assignment tests' stamp: ' 7/9/05 23:28'! testArithmetic "self run: #testArithmetic" | collector | collector := self doForSource: 'u := v \\ 3. a := b floor. b := c truncateTo: (x := 4 roundTo: 5)'. self assertSends: #( #(v #(\\)) #(b #(floor)) #(c #(truncateTo:))) in: collector. self assertAssignments: #(#(u #(Number)) #(a #(Number)) #(b #(Number)) #(x #(Number))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'assignment tests' stamp: ' 7/9/05 23:28'! testArrayAssignment | collector | collector := self doForSource: 'v := #(one two three)'. self assertAssignments: #(#(v #(#Array))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testCascaded1 | collector | collector := self doForSource: 'x printString; size'. self assertSends: #(#(x #(#printString #size))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testCascaded2 | collector | collector := self doForSource: 'x printString; size; yourself'. self assertSends: #(#(x #(#printString #size #yourself))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'assignment tests' stamp: ' 7/9/05 23:28'! testComplicated1 | collector | collector := self doForSource: ' b := Set new: 3 * (c collect: [:s | s])'. self assertSends: #( #(c #(collect:)) ) in: collector. self assertAssignments: #(#(b #(#Set))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'non supported' stamp: ' 7/9/05 23:28'! testComplicated2 | collector | collector := self doForSource: ' | temp1 temp2 | temp1 := b := temp2 := 3.'. self denyAssignments: #(#(b #(#SmallInteger))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'non supported' stamp: ' 7/9/05 23:28'! testComplicated3 "self run: #testComplicated3" "selfdebug: #testComplicated3" | collector | collector := self doForSource: ' | temp1 temp2 temp3 | temp2 := b := temp1 := 3.'. self denyAssignments: #(#(b #(#SmallInteger))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'assignment tests' stamp: ' 7/9/05 23:28'! testEquality | collector | collector := self doForSource: 'u := v = 3'. self assertSends: #(#(v #(#=))) in: collector. self assertAssignments: #(#(u #(#Boolean))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'assignment tests' stamp: ' 7/9/05 23:28'! testIdentity | collector | collector := self doForSource: 'u := v == 3'. self assertSends: #(#(v #(#==))) in: collector. self assertAssignments: #(#(u #(#Boolean))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testIftrue | vSends collector | collector := self doForSource: 'u := v isNil ifTrue: [1] ifFalse: [2]'. vSends := collector sendsTo: #v. self assert: (vSends size = 1). self assert: (vSends includes: #isNil).! ! !InstvarInterfaceExtractorTest methodsFor: 'assignment tests' stamp: ' 7/9/05 23:28'! testInstanceAssignment | collector | collector := self doForSource: 'w := TypeCollector new'. self assertAssignments: #(#(w #(#TypeCollector))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'assignment tests' stamp: ' 7/9/05 23:28'! testInstanceAssignmentIndirect | collector | collector := self doForSource: 'self w: TypeCollector new'. self assertAssignments: #(#(w #(#TypeCollector))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'assignment tests' stamp: ' 7/9/05 23:28'! testInstvarAssignment1 | collector | collector := self doForSource: ' | temp1 temp2 temp3 | a := 3. b := a'. self assertAssignments: #(#(b #(#SmallInteger)) (a #(#SmallInteger))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'assignment tests' stamp: ' 7/9/05 23:28'! testInstvarAssignment2 | collector | collector := self doForSource: ' | temp1 temp2 temp3 | c := b := 3.'. self assertAssignments: #(#(b #(#SmallInteger)) (c #(#SmallInteger))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'assignment tests' stamp: ' 7/9/05 23:28'! testMetaClassAssignment | collector wAssignments wIndex | collector := self doForSource: 'w := TypeCollector'. wIndex := collector indexForVar: #w. wAssignments := collector assignmentsTo: #w. self assert: wAssignments size = 1. self assert: (wAssignments includes: TypeCollector class). self emptyAssigment: collector typingResults atIndexes: ((1 to: self class instVarNames size) asOrderedCollection remove: wIndex; yourself)! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testSuperivarAssignment | collector | collector := self doForSource: '^testSelector := testSelector'. self assertSends: #() in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testSuperivarSend | collector | collector := self doForSource: '^testSelector printString'. self assertSends: #( #(testSelector #(#printString)) ) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testblockindirectxy | collector | collector := self doForSource: '^self testu ifTrue: [self x] ifFalse: [self y asString]'. self assertSends: #(#(y #(#asString))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testblockuwx | collector | collector := self doForSource: '^[u + w] on: Error do: [:exc | x printString]'. self assertSends: #(#(u #(#+)) #(x #(#printString))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testblockxy | collector | collector := self doForSource: '^self xyw ifTrue: [x] ifFalse: [y]'. self assertSends: #() in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testblockyab " #'ifTrue:ifFalse: is sent to a, but is not Captured by the extractor" | collector | collector := self doForSource: '^self a ifTrue: [b] ifFalse: [y]'. self assertSends: #() in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testindirectx | collector | collector := self doForSource: '^self x printString'. self assertSends: #(#(x #(#printString))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testu | collector | collector := self doForSource: '^u'. self assertSends: #() in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testuxyw | collector | collector := self doForSource: ' u := (x asString ~= y printString). ^u = w'. self assertSends: #(#(y #(#printString)) #(x #(#asString)) #(u #(#=))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testxyw | collector | collector := self doForSource: ' | t | t := (x = y). ^t = w'. self assertSends: #(#(x #(#=))) in: collector! ! !InstvarInterfaceExtractorTest methodsFor: 'send tests' stamp: ' 7/9/05 23:28'! testzuv | collector | collector := self doForSource: '^u ~= z or: [u = v]'. self assertSends: #(#(u #(#= #~=))) in: collector! ! !RoelTypingTestRoot methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! doForSource: src | m | m := (Compiler new compile: ('gen ', src) in: self class notifying: nil ifFail: [self error: 'Error during compilation of generated method.']) generate. ^self processMethod: m.! ! !RoelTypingTestRoot methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! processMethod: aCompiledMethod "Fail by default. Needs to be overridden by subclasses to trigger the base testing backbone." self assert: false! ! RoelTypingTestRoot subclass: #TypeCheckingTests instanceVariableNames: 'typeResultKeeper ivarForTests' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Tests'! !TypeCheckingTests methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! processMethod: aCompiledMethod "Fail by default. Needs to be overridden by subclasses to trigger the base testing backbone." | collector invalidatedTypes existingTypeResult instvarUsed extractedInterface | instvarUsed := #ivarForTests. collector := TypeCollector onClass: self class. invalidatedTypes := Set new. TypeCollector new newExtractor extractInterfacesFrom: aCompiledMethod addTo: collector. extractedInterface := collector sendsTo: instvarUsed. existingTypeResult := (typeResultKeeper typesForClass: self class instvar: instvarUsed) types. extractedInterface do: [:selector | invalidatedTypes addAll: (existingTypeResult select: [:existingType | (existingType canUnderstand: selector) not]) ]. ^invalidatedTypes! ! !TypeCheckingTests methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! setMultipleTypeAs: existingClasses "I am faking the typeResultKeeper to hold a given set of types for the ivarForText instance variable used in the tests." | collector index | typeResultKeeper := TypingResultKeeper new. collector := TypeCollector onClass: self class. index := collector indexForVar: #ivarForTests. existingClasses do: [:existingClass | collector addAssignment: existingClass to: index-1]. typeResultKeeper addCollectorResult: collector packagedResults! ! !TypeCheckingTests methodsFor: 'auxiliary' stamp: ' 7/9/05 23:28'! setTypeAs: existingClass "I am faking the typeResultKeeper to hold a given set of types for the ivarForText instance variable used in the tests." self setMultipleTypeAs: (Array with: existingClass)! ! !TypeCheckingTests methodsFor: 'testing' stamp: ' 7/9/05 23:28'! testSetTestCaseAdd | diffs | self setMultipleTypeAs: (Array with: Set with: TestCase). diffs := self doForSource: 'ivarForTests add: 4'. self assert: (diffs size = 1). self assert: (diffs includes: TestCase)! ! !TypeCheckingTests methodsFor: 'testing' stamp: ' 7/9/05 23:28'! testSetTestCaseAssert | diffs | self setMultipleTypeAs: (Array with: Set with: TestCase). diffs := self doForSource: '^ivarForTests resources'. self assert: (diffs size = 1). self assert: (diffs includes: Set)! ! !TypeCheckingTests methodsFor: 'testing' stamp: ' 7/9/05 23:28'! testSetTestCaseClass | diffs | self setMultipleTypeAs: (Array with: Set with: TestCase). diffs := self doForSource: 'ivarForTests class'. self assert: diffs isEmpty! ! !TypeCheckingTests methodsFor: 'testing' stamp: ' 7/9/05 23:28'! testSetTestCaseFoo | diffs | self setMultipleTypeAs: (Array with: Set with: TestCase). diffs := self doForSource: 'ivarForTests foo'. self assert: (diffs size = 2). self assert: (diffs includes: Set). self assert: (diffs includes: TestCase)! ! !TypeCheckingTests methodsFor: 'testing' stamp: ' 7/9/05 23:28'! testSetadd | diffs | self setTypeAs: Set. diffs := self doForSource: 'ivarForTests add: 2'. self assert: diffs isEmpty! ! !TypeCheckingTests methodsFor: 'testing' stamp: ' 7/9/05 23:28'! testSetfoo | diffs | self setTypeAs: Set. diffs := self doForSource: 'ivarForTests foo'. self assert: diffs size = 1! ! TestCase subclass: #TypeCollectorTests instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Tests'! !TypeCollectorTests methodsFor: 'typing tests' stamp: ' 7/9/05 23:28'! testPoint | types xTypes yTypes | types := TypeCollector typeInstvarsOfClass: Point. xTypes := types at: #x. self assert: ((xTypes is: Number) or: [xTypes is: Integer]). yTypes := types at: #y. self assert: ((yTypes is: Number) or: [yTypes is: Integer])! ! TestCase subclass: #TypingResultTests instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'RoelTyper-Tests'! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test1 "Array is subclass of Collection -> folding keeps Array and loses Collection" | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: Collection) with: (OrderedCollection with: Array). self assert: foldingResult size = 1. self assert: foldingResult first = Array.! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test10 "Dictionary and Array are in unrelated hierarchies -> keep both. Collection bites the dust because it is superclass of OrderedCollection" | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: Dictionary) with: (OrderedCollection with: Array with: Collection). self assert: foldingResult size = 2. self assert: (foldingResult includes: Dictionary). self assert: (foldingResult includes: Array).! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test11 "Dictionary and Array are in unrelated hierarchies -> keep both. Collection bites the dust because it is superclass of OrderedCollection" | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: Dictionary) with: (OrderedCollection with: Collection with: Array ). self assert: foldingResult size = 2. self assert: (foldingResult includes: Dictionary). self assert: (foldingResult includes: Array).! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test12 "Dictionary and Array are in unrelated hierarchies -> keep both. Collection bites the dust because it is superclass." | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: Collection) with: (OrderedCollection with: Dictionary with: Array ). self assert: foldingResult size = 2. self assert: (foldingResult includes: Dictionary). self assert: (foldingResult includes: Array).! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test13 "Dictionary and Array are in unrelated hierarchies -> keep both. Collection bites the dust because it is superclass." | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: Collection) with: (OrderedCollection with: Array with: Dictionary). self assert: foldingResult size = 2. self assert: (foldingResult includes: Dictionary). self assert: (foldingResult includes: Array).! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test14 | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: SequenceableCollection with: Bag) with: (OrderedCollection with: Array). self assert: foldingResult size = 2. self assert: (foldingResult includes: Array). self assert: (foldingResult includes: Bag).! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test2 "Array is subclass of Collection -> folding keeps Array and loses Collection" | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: Array) with: (OrderedCollection with: Collection). self assert: foldingResult size = 1. self assert: foldingResult first = Array.! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test3 | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection new) with: (OrderedCollection new). self assert: foldingResult size = 1. self assert: foldingResult first = Object! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test4 | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: Object) with: (OrderedCollection new). self assert: foldingResult size = 1. self assert: foldingResult first = Object! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test5 | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection new) with: (OrderedCollection with: Object). self assert: foldingResult size = 1. self assert: foldingResult first = Object! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test6 "Dictionary and Array are in unrelated hierarchies -> keep both" | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: Dictionary) with: (OrderedCollection with: Array). self assert: foldingResult size = 2. self assert: (foldingResult includes: Dictionary). self assert: (foldingResult includes: Array).! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test7 "Dictionary and Array are in unrelated hierarchies -> keep both" | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: Dictionary with: Object) with: (OrderedCollection with: Array). self assert: foldingResult size = 2. self assert: (foldingResult includes: Dictionary). self assert: (foldingResult includes: Array).! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test8 "Dictionary and Array are in unrelated hierarchies -> keep both" | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: Dictionary) with: (OrderedCollection with: Array with: Object). self assert: foldingResult size = 2. self assert: (foldingResult includes: Dictionary). self assert: (foldingResult includes: Array).! ! !TypingResultTests methodsFor: 'folding tests' stamp: ' 7/9/05 23:28'! test9 "Dictionary and Array are in unrelated hierarchies -> keep both" | foldingResult | foldingResult := ExtractedType basicNew fold: (OrderedCollection with: Dictionary with: Object) with: (OrderedCollection with: Array with: Object). self assert: foldingResult size = 2. self assert: (foldingResult includes: Dictionary). self assert: (foldingResult includes: Array).! ! !TypingResultTests methodsFor: 'actions' stamp: ' 7/9/05 23:28'! testChecking! ! !TypingResultTests methodsFor: 'indicatesSameTypes tests' stamp: ' 7/9/05 23:28'! testIndicatesSame1 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #findElementOrNil: with: #do:) assignments: IdentitySet new. result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #collect:) assignments: IdentitySet new. self deny: (result2 isConformingTo: result1). self assert: (result1 isConformingTo: result2).! ! !TypingResultTests methodsFor: 'indicatesSameTypes tests' stamp: ' 7/9/05 23:28'! testIndicatesSame2 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #testIndicatesSame1 with: #testSame1) assignments: IdentitySet new. result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #do: with: #testIndicatesSame1 with: #testSame1) assignments: IdentitySet new. self deny: (result2 isConformingTo: result1)! ! !TypingResultTests methodsFor: 'indicatesSameTypes tests' stamp: ' 7/9/05 23:28'! testIndicatesSame3 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #testIndicatesSame1 with: #testSame1) assignments: IdentitySet new. result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #testSame2 with: #testIndicatesSame1 with: #testSame1) assignments: IdentitySet new. self assert: (result2 isConformingTo: result1)! ! !TypingResultTests methodsFor: 'indicatesSameTypes tests' stamp: ' 7/9/05 23:28'! testIndicatesSame4 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet new) assignments: IdentitySet new. result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet new) assignments: IdentitySet new. self assert: (result2 isConformingTo: result1)! ! !TypingResultTests methodsFor: 'indicatesSameTypes tests' stamp: ' 7/9/05 23:28'! testIndicatesSame5 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet new) assignments: (IdentitySet with: Array with: Set). result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet new) assignments: (IdentitySet with: Set). self deny: (result2 isConformingTo: result1)! ! !TypingResultTests methodsFor: 'sameAs tests' stamp: ' 7/9/05 23:28'! testSame1 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: IdentitySet new. result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: IdentitySet new. self assert: (result1 sameAs: result2)! ! !TypingResultTests methodsFor: 'sameAs tests' stamp: ' 7/9/05 23:28'! testSame2 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: IdentitySet new assignments: (IdentitySet with: OrderedCollection). result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: IdentitySet new assignments: (IdentitySet with: OrderedCollection). self assert: (result1 sameAs: result2)! ! !TypingResultTests methodsFor: 'sameAs tests' stamp: ' 7/9/05 23:28'! testSame3 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: (IdentitySet with: OrderedCollection). result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: (IdentitySet with: OrderedCollection). self assert: (result1 sameAs: result2)! ! !TypingResultTests methodsFor: 'sameAs tests' stamp: ' 7/9/05 23:28'! testSame4 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet new) assignments: (IdentitySet with: OrderedCollection). result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: (IdentitySet with: OrderedCollection). self deny: (result1 sameAs: result2)! ! !TypingResultTests methodsFor: 'sameAs tests' stamp: ' 7/9/05 23:28'! testSame5 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet new) assignments: (IdentitySet new). result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: (IdentitySet with: OrderedCollection). self deny: (result1 sameAs: result2)! ! !TypingResultTests methodsFor: 'sameAs tests' stamp: ' 7/9/05 23:28'! testSame6 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: (IdentitySet new). result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: (IdentitySet with: OrderedCollection). self deny: (result1 sameAs: result2)! ! !TypingResultTests methodsFor: 'sameAs tests' stamp: ' 7/9/05 23:28'! testSame7 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #bar) assignments: (IdentitySet with: OrderedCollection). result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: (IdentitySet with: OrderedCollection). self deny: (result1 sameAs: result2)! ! !TypingResultTests methodsFor: 'sameAs tests' stamp: ' 7/9/05 23:28'! testSame8 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #bar) assignments: (IdentitySet with: Array). result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: (IdentitySet with: OrderedCollection). self deny: (result1 sameAs: result2)! ! !TypingResultTests methodsFor: 'sameAs tests' stamp: ' 7/9/05 23:28'! testSame9 | result1 result2 | result1 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: (IdentitySet with: Array). result2 := ExtractedType forInstvar: #testSelector inClass: self class interface: (IdentitySet with: #foo) assignments: (IdentitySet with: OrderedCollection). self deny: (result1 sameAs: result2)! !