@@ -64,42 +64,27 @@ extension TranslatorContext {
6464extension InternalInstance : TranslatorContext {
6565 func resolveType( _ index: TypeIndex ) throws -> FunctionType {
6666 guard Int ( index) < self . types. count else {
67- throw TranslationError ( " Type index \( index ) is out of range " )
67+ throw ValidationError ( . indexOutOfBounds ( " type " , index, max : UInt32 ( self . types . count ) ) )
6868 }
6969 return self . types [ Int ( index) ]
7070 }
7171 func resolveBlockType( _ blockType: BlockType ) throws -> FunctionType {
7272 try FunctionType ( blockType: blockType, typeSection: self . types)
7373 }
7474 func functionType( _ index: FunctionIndex , interner: Interner < FunctionType > ) throws -> FunctionType {
75- guard Int ( index) < self . functions. count else {
76- throw TranslationError ( " Function index \( index) is out of range " )
77- }
78- return interner. resolve ( self . functions [ Int ( index) ] . type)
75+ return try interner. resolve ( self . functions [ validating: Int ( index) ] . type)
7976 }
8077 func globalType( _ index: GlobalIndex ) throws -> ValueType {
81- guard Int ( index) < self . globals. count else {
82- throw TranslationError ( " Global index \( index) is out of range " )
83- }
84- return self . globals [ Int ( index) ] . globalType. valueType
78+ return try self . globals [ validating: Int ( index) ] . globalType. valueType
8579 }
8680 func isMemory64( memoryIndex index: MemoryIndex ) throws -> Bool {
87- guard Int ( index) < self . memories. count else {
88- throw TranslationError ( " Memory index \( index) is out of range " )
89- }
90- return self . memories [ Int ( index) ] . limit. isMemory64
81+ return try self . memories [ validating: Int ( index) ] . limit. isMemory64
9182 }
9283 func isMemory64( tableIndex index: TableIndex ) throws -> Bool {
93- guard Int ( index) < self . tables. count else {
94- throw TranslationError ( " Table index \( index) is out of range " )
95- }
96- return self . tables [ Int ( index) ] . limits. isMemory64
84+ return try self . tables [ validating: Int ( index) ] . limits. isMemory64
9785 }
9886 func tableType( _ index: TableIndex ) throws -> TableType {
99- guard Int ( index) < self . tables. count else {
100- throw TranslationError ( " Table index \( index) is out of range " )
101- }
102- return self . tables [ Int ( index) ] . tableType
87+ return try self . tables [ validating: Int ( index) ] . tableType
10388 }
10489 func elementType( _ index: ElementIndex ) throws -> ReferenceType {
10590 try self . elementSegments [ validating: Int ( index) ] . type
@@ -117,7 +102,7 @@ extension InternalInstance: TranslatorContext {
117102 func validateFunctionIndex( _ index: FunctionIndex ) throws {
118103 let function = try self . functions [ validating: Int ( index) ]
119104 guard self . functionRefs. contains ( function) else {
120- throw ValidationError ( " Function index \( index) is not declared but referenced as a function reference " )
105+ throw ValidationError ( . functionIndexNotDeclared ( index: index) )
121106 }
122107 }
123108 var dataCount : UInt32 ? {
@@ -354,22 +339,22 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
354339
355340 private mutating func setReachability( _ value: Bool ) throws {
356341 guard !self . frames. isEmpty else {
357- throw ValidationError ( " Control stack is empty. Instruction cannot be appeared after \" end \" of function " )
342+ throw ValidationError ( . controlStackEmpty )
358343 }
359344 self . frames [ self . frames. count - 1 ] . reachable = value
360345 }
361346
362347 func currentFrame( ) throws -> ControlFrame {
363348 guard let frame = self . frames. last else {
364- throw ValidationError ( " Control stack is empty. Instruction cannot be appeared after \" end \" of function " )
349+ throw ValidationError ( . controlStackEmpty )
365350 }
366351 return frame
367352 }
368353
369354 func branchTarget( relativeDepth: UInt32 ) throws -> ControlFrame {
370355 let index = frames. count - 1 - Int( relativeDepth)
371356 guard frames. indices. contains ( index) else {
372- throw ValidationError ( " Relative depth \ ( relativeDepth) is out of range " )
357+ throw ValidationError ( . relativeDepthOutOfRange ( relativeDepth: relativeDepth ) )
373358 }
374359 return frames [ index]
375360 }
@@ -1012,7 +997,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1012997 switch actual {
1013998 case . some( let actualType) :
1014999 guard actualType == type else {
1015- throw ValidationError ( " Expected \( type) on the stack top but got \( actualType) " )
1000+ throw ValidationError ( . expectedTypeOnStack ( expected : type, actual : actualType) )
10161001 }
10171002 case . unknown: break
10181003 }
@@ -1075,7 +1060,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
10751060
10761061 private mutating func finalize( ) throws -> InstructionSequence {
10771062 if controlStack. numberOfFrames > 1 {
1078- throw TranslationError ( " Expect \( controlStack. numberOfFrames - 1 ) more `end` instructions " )
1063+ throw ValidationError ( . expectedMoreEndInstructions ( count : controlStack. numberOfFrames - 1 ) )
10791064 }
10801065 // Check dangling labels
10811066 try iseqBuilder. assertDanglingLabels ( )
@@ -1187,7 +1172,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
11871172 mutating func visitElse( ) throws -> Output {
11881173 var frame = try controlStack. currentFrame ( )
11891174 guard case let . if( elseLabel, endLabel, _) = frame. kind else {
1190- throw TranslationError ( " Expected `if` control frame on top of the stack for `else` but got \( frame ) " )
1175+ throw ValidationError ( . expectedIfControlFrame )
11911176 }
11921177 preserveOnStack ( depth: valueStack. height - frame. stackHeight)
11931178 try controlStack. resetReachability ( )
@@ -1201,7 +1186,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12011186 _ = try valueStack. pop ( result)
12021187 }
12031188 guard valueStack. height == frame. stackHeight else {
1204- throw ValidationError ( " values remaining on stack at end of block " )
1189+ throw ValidationError ( . valuesRemainingAtEndOfBlock )
12051190 }
12061191 _ = controlStack. popFrame ( )
12071192 frame. kind = . if( elseLabel: elseLabel, endLabel: endLabel, isElse: true )
@@ -1217,40 +1202,23 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12171202
12181203 mutating func visitEnd( ) throws -> Output {
12191204 let toBePopped = try controlStack. currentFrame ( )
1220- // Reset the last emission to avoid relinking the result of the last instruction inside the block.
1221- // Relinking results across the block boundary is invalid because the producer instruction is not
1222- // statically known. Think about the following case:
1223- // ```
1224- // local.get 0
1225- // if
1226- // i32.const 2
1227- // else
1228- // i32.const 3
1229- // end
1230- // local.set 0
1231- // ```
1232- //
12331205 iseqBuilder. resetLastEmission ( )
12341206 if case . block( root: true ) = toBePopped. kind {
12351207 try translateReturn ( )
1236- // TODO: Merge logic with regular block frame
12371208 guard valueStack. height == toBePopped. stackHeight else {
1238- throw ValidationError ( " values remaining on stack at end of block " )
1209+ throw ValidationError ( . valuesRemainingAtEndOfBlock )
12391210 }
12401211 try iseqBuilder. pinLabelHere ( toBePopped. continuation)
12411212 return
12421213 }
12431214
12441215 if case . if( _, _, isElse: false ) = toBePopped. kind {
1245- // `if` inst without `else` must have the same parameter and result types
12461216 let blockType = toBePopped. blockType
12471217 guard blockType. parameters == blockType. results else {
1248- throw TranslationError ( " Expected the same parameter and result types for `if` block but got \ ( blockType) " )
1218+ throw ValidationError ( . parameterResultTypeMismatch ( blockType: blockType ) )
12491219 }
12501220 }
12511221
1252- // NOTE: `valueStack.height - poppedFrame.stackHeight` is usually the same as `poppedFrame.copyCount`
1253- // but it's not always the case when this block is already unreachable.
12541222 preserveOnStack ( depth: Int ( valueStack. height - toBePopped. stackHeight) )
12551223 switch toBePopped. kind {
12561224 case . block:
@@ -1264,7 +1232,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12641232 _ = try valueStack. pop ( result)
12651233 }
12661234 guard valueStack. height == toBePopped. stackHeight else {
1267- throw ValidationError ( " values remaining on stack at end of block " )
1235+ throw ValidationError ( . valuesRemainingAtEndOfBlock )
12681236 }
12691237 for result in toBePopped. blockType. results {
12701238 _ = valueStack. push ( result)
@@ -1281,7 +1249,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12811249 if _fastPath ( currentFrame. reachable) {
12821250 let count = currentHeight - Int( destination. copyCount) - destination. stackHeight
12831251 guard count >= 0 else {
1284- throw TranslationError ( " Stack height underflow: available \( currentHeight) , required \( destination. stackHeight + Int( destination. copyCount) ) " )
1252+ throw ValidationError ( . stackHeightUnderflow ( available : currentHeight, required: destination. stackHeight + Int( destination. copyCount) ) )
12851253 }
12861254 popCount = UInt32 ( count)
12871255 } else {
@@ -1437,7 +1405,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
14371405
14381406 // Check copyTypes consistency
14391407 guard frame. copyTypes. count == defaultFrame. copyTypes. count else {
1440- throw ValidationError ( " Expected the same copy types for all branches in `br_table` but got \( frame. copyTypes) and \( defaultFrame. copyTypes) " )
1408+ throw ValidationError ( . expectedSameCopyTypes ( frameCopyTypes : frame. copyTypes, defaultFrameCopyTypes : defaultFrame. copyTypes) )
14411409 }
14421410 try checkStackTop ( frame. copyTypes)
14431411
@@ -1528,10 +1496,10 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
15281496 let ( value2Type, value2) = try popAnyOperand ( )
15291497 switch ( value1Type, value2Type) {
15301498 case ( . some( . ref( _) ) , _) , ( _, . some( . ref( _) ) ) :
1531- throw TranslationError ( " Cannot `select` on reference types " )
1499+ throw ValidationError ( . cannotSelectOnReferenceTypes )
15321500 case let ( . some( type1) , . some( type2) ) :
15331501 guard type1 == type2 else {
1534- throw TranslationError ( " Type mismatch on `select`. Expected \( value1Type ) and \( value2Type ) to be same " )
1502+ throw ValidationError ( . typeMismatchOnSelect ( expected : type1 , actual : type2 ) )
15351503 }
15361504 case ( . unknown, _) , ( _, . unknown) :
15371505 break
@@ -2213,7 +2181,7 @@ extension FunctionType {
22132181 case let . funcType( typeIndex) :
22142182 let typeIndex = Int ( typeIndex)
22152183 guard typeIndex < typeSection. count else {
2216- throw ValidationError ( " type index out of bounds: accessed \( typeIndex) , but only \( typeSection. count) types are defined " )
2184+ throw ValidationError ( . indexOutOfBounds ( " type " , typeIndex, max : typeSection. count) )
22172185 }
22182186 let funcType = typeSection [ typeIndex]
22192187 self . init (
0 commit comments