@@ -3855,6 +3855,8 @@ export class Compiler extends DiagnosticEmitter {
38553855 private f64ModInstance : Function | null = null ;
38563856 private f32PowInstance : Function | null = null ;
38573857 private f64PowInstance : Function | null = null ;
3858+ private i32PowInstance : Function | null = null ;
3859+ private i64PowInstance : Function | null = null ;
38583860
38593861 private compileBinaryExpression (
38603862 expression : BinaryExpression ,
@@ -4786,82 +4788,198 @@ export class Compiler extends DiagnosticEmitter {
47864788 ) ;
47874789 return this . module . unreachable ( ) ;
47884790 }
4791+ if ( compound ) {
4792+ leftExpr = this . ensureSmallIntegerWrap ( leftExpr , leftType ) ;
4793+ rightExpr = this . compileExpression ( right , leftType , Constraints . CONV_IMPLICIT ) ;
4794+ rightType = commonType = this . currentType ;
4795+ } else {
4796+ rightExpr = this . compileExpression ( right , leftType ) ;
4797+ rightType = this . currentType ;
4798+ commonType = Type . commonDenominator ( leftType , rightType , false ) ;
4799+ if ( commonType ) {
4800+ leftExpr = this . convertExpression ( leftExpr ,
4801+ leftType , commonType ,
4802+ false , true , // !
4803+ left
4804+ ) ;
4805+ leftType = commonType ;
4806+ rightExpr = this . convertExpression ( rightExpr ,
4807+ rightType , commonType ,
4808+ false , true , // !
4809+ right
4810+ ) ;
4811+ rightType = commonType ;
4812+ } else {
4813+ this . error (
4814+ DiagnosticCode . Operator_0_cannot_be_applied_to_types_1_and_2 ,
4815+ expression . range , "**" , leftType . toString ( ) , rightType . toString ( )
4816+ ) ;
4817+ this . currentType = contextualType ;
4818+ return module . unreachable ( ) ;
4819+ }
4820+ }
47894821
4790- let targetType = leftType ;
47914822 let instance : Function | null ;
4792-
4793- // Mathf.pow if lhs is f32 (result is f32)
4794- if ( this . currentType . kind == TypeKind . F32 ) {
4795- rightExpr = this . compileExpression ( right , Type . f32 , Constraints . CONV_IMPLICIT ) ;
4796- rightType = this . currentType ;
4797- instance = this . f32PowInstance ;
4798- if ( ! instance ) {
4799- let namespace = this . program . lookupGlobal ( CommonNames . Mathf ) ;
4800- if ( ! namespace ) {
4801- this . error (
4802- DiagnosticCode . Cannot_find_name_0 ,
4803- expression . range , "Mathf"
4804- ) ;
4823+ switch ( commonType . kind ) {
4824+ case TypeKind . BOOL : {
4825+ expr = module . select (
4826+ module . i32 ( 1 ) ,
4827+ module . binary ( BinaryOp . EqI32 , rightExpr , module . i32 ( 0 ) ) ,
4828+ leftExpr
4829+ ) ;
4830+ break ;
4831+ }
4832+ case TypeKind . I8 :
4833+ case TypeKind . U8 :
4834+ case TypeKind . I16 :
4835+ case TypeKind . U16 :
4836+ case TypeKind . I32 :
4837+ case TypeKind . U32 : {
4838+ instance = this . i32PowInstance ;
4839+ if ( ! instance ) {
4840+ let prototype = this . program . lookupGlobal ( CommonNames . ipow32 ) ;
4841+ if ( ! prototype ) {
4842+ this . error (
4843+ DiagnosticCode . Cannot_find_name_0 ,
4844+ expression . range , "ipow32"
4845+ ) ;
4846+ expr = module . unreachable ( ) ;
4847+ break ;
4848+ }
4849+ assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4850+ this . i32PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4851+ }
4852+ if ( ! instance || ! this . compileFunction ( instance ) ) {
48054853 expr = module . unreachable ( ) ;
4806- break ;
4854+ } else {
4855+ expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
4856+ if ( commonType . size != 32 ) {
4857+ expr = this . ensureSmallIntegerWrap ( expr , commonType ) ;
4858+ }
48074859 }
4808- let namespaceMembers = namespace . members ;
4809- if ( ! namespaceMembers || ! namespaceMembers . has ( CommonNames . pow ) ) {
4810- this . error (
4811- DiagnosticCode . Cannot_find_name_0 ,
4812- expression . range , "Mathf.pow"
4813- ) ;
4860+ break ;
4861+ }
4862+ case TypeKind . I64 :
4863+ case TypeKind . U64 : {
4864+ instance = this . i64PowInstance ;
4865+ if ( ! instance ) {
4866+ let prototype = this . program . lookupGlobal ( CommonNames . ipow64 ) ;
4867+ if ( ! prototype ) {
4868+ this . error (
4869+ DiagnosticCode . Cannot_find_name_0 ,
4870+ expression . range , "ipow64"
4871+ ) ;
4872+ expr = module . unreachable ( ) ;
4873+ break ;
4874+ }
4875+ assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4876+ this . i64PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4877+ }
4878+ if ( ! instance || ! this . compileFunction ( instance ) ) {
48144879 expr = module . unreachable ( ) ;
4815- break ;
4880+ } else {
4881+ expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
48164882 }
4817- let prototype = assert ( namespaceMembers . get ( CommonNames . pow ) ) ;
4818- assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4819- this . f32PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4883+ break ;
48204884 }
4821-
4822- // Math.pow otherwise (result is f64)
4823- // TODO: should the result be converted back?
4824- } else {
4825- leftExpr = this . convertExpression ( leftExpr ,
4826- this . currentType , Type . f64 ,
4827- false , false ,
4828- left
4829- ) ;
4830- leftType = this . currentType ;
4831- rightExpr = this . compileExpression ( right , Type . f64 , Constraints . CONV_IMPLICIT ) ;
4832- rightType = this . currentType ;
4833- instance = this . f64PowInstance ;
4834- if ( ! instance ) {
4835- let namespace = this . program . lookupGlobal ( CommonNames . Math ) ;
4836- if ( ! namespace ) {
4837- this . error (
4838- DiagnosticCode . Cannot_find_name_0 ,
4839- expression . range , "Math"
4840- ) ;
4885+ case TypeKind . ISIZE :
4886+ case TypeKind . USIZE : {
4887+ let isWasm64 = this . options . isWasm64 ;
4888+ instance = isWasm64 ? this . i64PowInstance : this . i32PowInstance ;
4889+ if ( ! instance ) {
4890+ let prototype = this . program . lookupGlobal ( isWasm64 ? CommonNames . ipow64 : CommonNames . ipow32 ) ;
4891+ if ( ! prototype ) {
4892+ this . error (
4893+ DiagnosticCode . Cannot_find_name_0 ,
4894+ expression . range , isWasm64 ? "ipow64" : "ipow32"
4895+ ) ;
4896+ expr = module . unreachable ( ) ;
4897+ break ;
4898+ }
4899+ assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4900+ instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4901+ if ( isWasm64 ) {
4902+ this . i64PowInstance = instance ;
4903+ } else {
4904+ this . i32PowInstance = instance ;
4905+ }
4906+ }
4907+ if ( ! instance || ! this . compileFunction ( instance ) ) {
48414908 expr = module . unreachable ( ) ;
4842- break ;
4909+ } else {
4910+ expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
48434911 }
4844- let namespaceMembers = namespace . members ;
4845- if ( ! namespaceMembers || ! namespaceMembers . has ( CommonNames . pow ) ) {
4846- this . error (
4847- DiagnosticCode . Cannot_find_name_0 ,
4848- expression . range , "Math.pow"
4849- ) ;
4912+ break ;
4913+ }
4914+ case TypeKind . F32 : {
4915+ instance = this . f32PowInstance ;
4916+ if ( ! instance ) {
4917+ let namespace = this . program . lookupGlobal ( CommonNames . Mathf ) ;
4918+ if ( ! namespace ) {
4919+ this . error (
4920+ DiagnosticCode . Cannot_find_name_0 ,
4921+ expression . range , "Mathf"
4922+ ) ;
4923+ expr = module . unreachable ( ) ;
4924+ break ;
4925+ }
4926+ let namespaceMembers = namespace . members ;
4927+ if ( ! namespaceMembers || ! namespaceMembers . has ( CommonNames . pow ) ) {
4928+ this . error (
4929+ DiagnosticCode . Cannot_find_name_0 ,
4930+ expression . range , "Mathf.pow"
4931+ ) ;
4932+ expr = module . unreachable ( ) ;
4933+ break ;
4934+ }
4935+ let prototype = assert ( namespaceMembers . get ( CommonNames . pow ) ) ;
4936+ assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4937+ this . f32PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4938+ }
4939+ if ( ! instance || ! this . compileFunction ( instance ) ) {
48504940 expr = module . unreachable ( ) ;
4851- break ;
4941+ } else {
4942+ expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
48524943 }
4853- let prototype = assert ( namespaceMembers . get ( CommonNames . pow ) ) ;
4854- assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4855- this . f64PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4944+ break ;
48564945 }
4857- }
4858- if ( ! instance || ! this . compileFunction ( instance ) ) {
4859- expr = module . unreachable ( ) ;
4860- } else {
4861- expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
4862- if ( compound && targetType != this . currentType ) {
4863- // this yields a proper error if target is i32 for example
4864- expr = this . convertExpression ( expr , this . currentType , targetType , false , false , expression ) ;
4946+ // Math.pow otherwise (result is f64)
4947+ case TypeKind . F64 : {
4948+ instance = this . f64PowInstance ;
4949+ if ( ! instance ) {
4950+ let namespace = this . program . lookupGlobal ( CommonNames . Math ) ;
4951+ if ( ! namespace ) {
4952+ this . error (
4953+ DiagnosticCode . Cannot_find_name_0 ,
4954+ expression . range , "Math"
4955+ ) ;
4956+ expr = module . unreachable ( ) ;
4957+ break ;
4958+ }
4959+ let namespaceMembers = namespace . members ;
4960+ if ( ! namespaceMembers || ! namespaceMembers . has ( CommonNames . pow ) ) {
4961+ this . error (
4962+ DiagnosticCode . Cannot_find_name_0 ,
4963+ expression . range , "Math.pow"
4964+ ) ;
4965+ expr = module . unreachable ( ) ;
4966+ break ;
4967+ }
4968+ let prototype = assert ( namespaceMembers . get ( CommonNames . pow ) ) ;
4969+ assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4970+ this . f64PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4971+ }
4972+ if ( ! instance || ! this . compileFunction ( instance ) ) {
4973+ expr = module . unreachable ( ) ;
4974+ } else {
4975+ expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
4976+ }
4977+ break ;
4978+ }
4979+ default : {
4980+ assert ( false ) ;
4981+ expr = module . unreachable ( ) ;
4982+ break ;
48654983 }
48664984 }
48674985 break ;
0 commit comments