@@ -8736,11 +8736,7 @@ export class Compiler extends DiagnosticEmitter {
87368736 break ;
87378737 }
87388738 case Token . TYPEOF : {
8739- this . error (
8740- DiagnosticCode . Operation_not_supported ,
8741- expression . range
8742- ) ;
8743- return module . unreachable ( ) ;
8739+ return this . compileTypeof ( expression , contextualType , constraints ) ;
87448740 }
87458741 default : {
87468742 assert ( false ) ;
@@ -8761,6 +8757,88 @@ export class Compiler extends DiagnosticEmitter {
87618757 ) ;
87628758 }
87638759
8760+ compileTypeof (
8761+ expression : UnaryPrefixExpression ,
8762+ contextualType : Type ,
8763+ constraints : Constraints
8764+ ) : ExpressionRef {
8765+ var operand = expression . operand ;
8766+ var expr : ExpressionRef = 0 ;
8767+ var stringInstance = this . program . stringInstance ;
8768+ var typeString : string ;
8769+ if ( operand . kind == NodeKind . NULL ) {
8770+ typeString = "object" ; // special since `null` without type context is usize
8771+ } else {
8772+ let element = this . resolver . lookupExpression ( operand , this . currentFlow , Type . auto , ReportMode . SWALLOW ) ;
8773+ if ( ! element ) {
8774+ switch ( operand . kind ) {
8775+ case NodeKind . PROPERTYACCESS :
8776+ case NodeKind . ELEMENTACCESS : {
8777+ operand = operand . kind == NodeKind . PROPERTYACCESS
8778+ ? ( < PropertyAccessExpression > operand ) . expression
8779+ : ( < ElementAccessExpression > operand ) . expression ;
8780+ let targetType = this . resolver . resolveExpression ( operand , this . currentFlow , Type . auto , ReportMode . REPORT ) ;
8781+ if ( ! targetType ) {
8782+ this . currentType = stringInstance . type ;
8783+ return this . module . unreachable ( ) ;
8784+ }
8785+ expr = this . compileExpression ( operand , Type . auto ) ; // might have side-effects
8786+ break ;
8787+ }
8788+ case NodeKind . IDENTIFIER : break ; // ignore error
8789+ default : expr = this . compileExpression ( operand , Type . auto ) ; // trigger error
8790+ }
8791+ typeString = "undefined" ;
8792+ } else {
8793+ switch ( element . kind ) {
8794+ case ElementKind . CLASS_PROTOTYPE :
8795+ case ElementKind . NAMESPACE :
8796+ case ElementKind . ENUM : {
8797+ typeString = "object" ;
8798+ break ;
8799+ }
8800+ case ElementKind . FUNCTION_PROTOTYPE : {
8801+ typeString = "function" ;
8802+ break ;
8803+ }
8804+ default : {
8805+ expr = this . compileExpression ( operand , Type . auto ) ;
8806+ let type = this . currentType ;
8807+ expr = this . convertExpression ( expr , type , Type . void , true , false , operand ) ;
8808+ if ( type . is ( TypeFlags . REFERENCE ) ) {
8809+ let signatureReference = type . signatureReference ;
8810+ if ( signatureReference ) {
8811+ typeString = "function" ;
8812+ } else {
8813+ let classReference = type . classReference ;
8814+ if ( classReference ) {
8815+ if ( classReference . prototype === stringInstance . prototype ) {
8816+ typeString = "string" ;
8817+ } else {
8818+ typeString = "object" ;
8819+ }
8820+ } else {
8821+ typeString = "anyref" ; // TODO?
8822+ }
8823+ }
8824+ } else if ( type == Type . bool ) {
8825+ typeString = "boolean" ;
8826+ } else if ( type . isAny ( TypeFlags . FLOAT | TypeFlags . INTEGER ) ) {
8827+ typeString = "number" ;
8828+ } else {
8829+ typeString = "undefined" ; // failed to compile?
8830+ }
8831+ break ;
8832+ }
8833+ }
8834+ }
8835+ }
8836+ this . currentType = stringInstance . type ;
8837+ return expr
8838+ ? this . module . block ( null , [ expr , this . ensureStaticString ( typeString ) ] , this . options . nativeSizeType )
8839+ : this . ensureStaticString ( typeString ) ;
8840+ }
8841+
87648842 /** Makes sure that a 32-bit integer value is wrapped to a valid value of the specified type. */
87658843 ensureSmallIntegerWrap ( expr : ExpressionRef , type : Type ) : ExpressionRef {
87668844 var module = this . module ;
0 commit comments