blob: 5152580901facbaad9439c7843bd3082abc2b471 [file] [log] [blame]
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart = 2.7
import 'native_testing.dart';
// Test that hidden native exception classes can be marked as existing.
//
// To infer which native hidden types exist, we need
// (1) return types of native methods and getters
// (2) argument types of callbacks
// (3) exceptions thrown by the operation.
//
// (1) and (2) can be achieved by having nicely typed native methods, but there
// is no place in the Dart language to communicate (3). So we use the following
// fake body technique.
// The exception type.
@Native("E")
class E {
E._used() native; // Bogus native constructor, called only from fake body.
int get code native;
}
// Type with exception-throwing methods.
@Native("A")
class A {
// Exception class E is created.
@Creates("E")
@Returns('int')
op(int x) native;
}
// This class is here just so that a dynamic context is polymorphic.
class B {
int get code => 666;
op(String x) => 123;
}
makeA() native;
void setup1() {
JS('', r"""
(function(){
// Ensure we are not relying on global names 'A' and 'E'.
self.A = null;
self.E = null;
})()""");
applyTestExtensions(['E', 'A']);
}
void setup2() {
JS('', r"""
(function(){
// Confirm A and B are null.
console.assert(self.A == null);
console.assert(self.B == null);
// This code is all inside 'setup2' and so not accessible from the global scope.
function E(x){ this.code = x; }
function A(){}
A.prototype.op = function (x) {
if (x & 1) throw new E(100);
return x / 2;
};
self.makeA = function(){return new A()};
self.nativeConstructor(E);
self.nativeConstructor(A);
})()""");
}
int inscrutable(int x) => x == 0 ? 0 : x | inscrutable(x & (x - 1));
main() {
nativeTesting();
setup1();
setup2();
var things = [makeA(), new B()];
var a = things[inscrutable(0)];
var b = things[inscrutable(1)];
Expect.equals(25, a.op(50));
Expect.equals(123, b.op('hello'));
Expect.equals(666, b.code);
bool threw = false;
try {
var x = a.op(51);
} catch (e) {
threw = true;
Expect.equals(100, e.code);
Expect.isTrue(e is E);
}
Expect.isTrue(threw);
// Again, but with statically typed receivers.
A aa = a;
B bb = b;
Expect.equals(25, aa.op(50));
Expect.equals(123, bb.op('hello'));
Expect.equals(666, bb.code);
threw = false;
try {
var x = aa.op(51);
} on E catch (e) {
threw = true;
Expect.equals(100, e.code);
Expect.isTrue(e is E);
}
Expect.isTrue(threw);
}