Skip to content

Commit 4b35d39

Browse files
committed
Revert "Void is not required to be null anymore."
This reverts commit 4e52c45. BUG= Review-Url: https://codereview.chromium.org/2863463002 .
1 parent 4752b67 commit 4b35d39

20 files changed

+104
-89
lines changed

CHANGELOG.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
## 1.24.0
22

33
### Language
4-
* During a dynamic type check, `void` is not required to be `null` anymore.
5-
In practice, this makes overriding `void` functions with non-`void` functions
6-
safer.
74

85
#### Strong Mode
96

pkg/compiler/lib/src/inferrer/type_graph_nodes.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1753,13 +1753,14 @@ TypeMask _narrowType(
17531753
{bool isNullable: true}) {
17541754
if (annotation.treatAsDynamic) return type;
17551755
if (annotation.isObject) return type;
1756-
if (annotation.isVoid) return type;
17571756
TypeMask otherType;
17581757
if (annotation.isTypedef || annotation.isFunctionType) {
17591758
otherType = closedWorld.commonMasks.functionType;
17601759
} else if (annotation.isTypeVariable) {
17611760
// TODO(ngeoffray): Narrow to bound.
17621761
return type;
1762+
} else if (annotation.isVoid) {
1763+
otherType = closedWorld.commonMasks.nullType;
17631764
} else {
17641765
ResolutionInterfaceType interfaceType = annotation;
17651766
otherType = new TypeMask.nonNullSubtype(interfaceType.element, closedWorld);

pkg/compiler/lib/src/inferrer/type_system.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ class TypeSystem {
282282
TypeInformation type, ResolutionDartType annotation,
283283
{bool isNullable: true}) {
284284
if (annotation.treatAsDynamic) return type;
285-
if (annotation.isVoid) return type;
285+
if (annotation.isVoid) return nullType;
286286
if (annotation.element == closedWorld.commonElements.objectClass &&
287287
isNullable) {
288288
return type;

pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class CheckedModeHelpers {
117117
/// All the checked mode helpers.
118118
static const List<CheckedModeHelper> helpers = const <CheckedModeHelper>[
119119
const MalformedCheckedModeHelper('checkMalformedType'),
120+
const CheckedModeHelper('voidTypeCheck'),
120121
const CheckedModeHelper('stringTypeCast'),
121122
const CheckedModeHelper('stringTypeCheck'),
122123
const CheckedModeHelper('doubleTypeCast'),
@@ -202,6 +203,12 @@ class CheckedModeHelpers {
202203
return 'checkMalformedType';
203204
}
204205

206+
if (type.isVoid) {
207+
assert(!typeCast); // Cannot cast to void.
208+
if (nativeCheckOnly) return null;
209+
return 'voidTypeCheck';
210+
}
211+
205212
if (type.isTypeVariable) {
206213
return typeCast
207214
? 'subtypeOfRuntimeTypeCast'

pkg/compiler/lib/src/js_backend/impact_transformer.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,6 @@ class CodegenImpactTransformer {
363363

364364
void onIsCheckForCodegen(DartType type, TransformedWorldImpact transformed) {
365365
if (type.isDynamic) return;
366-
if (type.isVoid) return;
367366
type = type.unaliased;
368367
_impacts.typeCheck.registerImpact(transformed, _elementEnvironment);
369368

pkg/compiler/lib/src/ssa/codegen.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2928,7 +2928,6 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
29282928
DartType type = node.typeExpression;
29292929
assert(!type.isTypedef);
29302930
assert(!type.isDynamic);
2931-
assert(!type.isVoid);
29322931
if (type.isFunctionType) {
29332932
// TODO(5022): We currently generate $isFunction checks for
29342933
// function types.

pkg/compiler/lib/src/ssa/nodes.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,9 +1342,8 @@ abstract class HInstruction implements Spannable {
13421342
assert(!type.isTypeVariable);
13431343
assert(type.treatAsRaw || type.isFunctionType);
13441344
if (type.isDynamic) return this;
1345-
if (type.isVoid) return this;
13461345
if (type == closedWorld.commonElements.objectType) return this;
1347-
if (type.isFunctionType || type.isMalformed) {
1346+
if (type.isVoid || type.isFunctionType || type.isMalformed) {
13481347
return new HTypeConversion(
13491348
type, kind, closedWorld.commonMasks.dynamicType, this);
13501349
}

runtime/vm/flow_graph_builder.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,9 +1259,8 @@ bool EffectGraphVisitor::CanSkipTypeCheck(TokenPosition token_pos,
12591259
return false;
12601260
}
12611261

1262-
// Any type is more specific than the dynamic type, the Object type, or void.
1263-
if (dst_type.IsDynamicType() || dst_type.IsObjectType() ||
1264-
dst_type.IsVoidType()) {
1262+
// Any type is more specific than the dynamic type and than the Object type.
1263+
if (dst_type.IsDynamicType() || dst_type.IsObjectType()) {
12651264
return true;
12661265
}
12671266

runtime/vm/flow_graph_compiler_arm.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,11 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
532532
Label* is_instance_lbl,
533533
Label* is_not_instance_lbl) {
534534
__ Comment("InlineInstanceof");
535+
if (type.IsVoidType()) {
536+
// A non-null value is returned from a void function, which will result in a
537+
// type error. A null value is handled prior to executing this inline code.
538+
return SubtypeTestCache::null();
539+
}
535540
if (type.IsInstantiated()) {
536541
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
537542
// A class equality check is only applicable with a dst type (not a
@@ -574,7 +579,7 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
574579
const AbstractType& type,
575580
LocationSummary* locs) {
576581
ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded());
577-
ASSERT(!type.IsObjectType() && !type.IsDynamicType() && !type.IsVoidType());
582+
ASSERT(!type.IsObjectType() && !type.IsDynamicType());
578583
const Register kInstantiatorTypeArgumentsReg = R2;
579584
const Register kFunctionTypeArgumentsReg = R1;
580585
__ PushList((1 << kInstantiatorTypeArgumentsReg) |
@@ -653,8 +658,7 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
653658
ASSERT(dst_type.IsFinalized());
654659
// Assignable check is skipped in FlowGraphBuilder, not here.
655660
ASSERT(dst_type.IsMalformedOrMalbounded() ||
656-
(!dst_type.IsDynamicType() && !dst_type.IsObjectType() &&
657-
!dst_type.IsVoidType()));
661+
(!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
658662
const Register kInstantiatorTypeArgumentsReg = R2;
659663
const Register kFunctionTypeArgumentsReg = R1;
660664
__ PushList((1 << kInstantiatorTypeArgumentsReg) |

runtime/vm/flow_graph_compiler_arm64.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,11 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
524524
Label* is_instance_lbl,
525525
Label* is_not_instance_lbl) {
526526
__ Comment("InlineInstanceof");
527+
if (type.IsVoidType()) {
528+
// A non-null value is returned from a void function, which will result in a
529+
// type error. A null value is handled prior to executing this inline code.
530+
return SubtypeTestCache::null();
531+
}
527532
if (type.IsInstantiated()) {
528533
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
529534
// A class equality check is only applicable with a dst type (not a
@@ -566,7 +571,7 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
566571
const AbstractType& type,
567572
LocationSummary* locs) {
568573
ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded());
569-
ASSERT(!type.IsObjectType() && !type.IsDynamicType() && !type.IsVoidType());
574+
ASSERT(!type.IsObjectType() && !type.IsDynamicType());
570575
const Register kInstantiatorTypeArgumentsReg = R1;
571576
const Register kFunctionTypeArgumentsReg = R2;
572577
__ PushPair(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
@@ -645,8 +650,7 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
645650
ASSERT(dst_type.IsFinalized());
646651
// Assignable check is skipped in FlowGraphBuilder, not here.
647652
ASSERT(dst_type.IsMalformedOrMalbounded() ||
648-
(!dst_type.IsDynamicType() && !dst_type.IsObjectType() &&
649-
!dst_type.IsVoidType()));
653+
(!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
650654
const Register kInstantiatorTypeArgumentsReg = R1;
651655
const Register kFunctionTypeArgumentsReg = R2;
652656
__ PushPair(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg);

runtime/vm/flow_graph_compiler_ia32.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,11 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
538538
Label* is_instance_lbl,
539539
Label* is_not_instance_lbl) {
540540
__ Comment("InlineInstanceof");
541+
if (type.IsVoidType()) {
542+
// A non-null value is returned from a void function, which will result in a
543+
// type error. A null value is handled prior to executing this inline code.
544+
return SubtypeTestCache::null();
545+
}
541546
if (type.IsInstantiated()) {
542547
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
543548
// A class equality check is only applicable with a dst type (not a
@@ -580,7 +585,7 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
580585
const AbstractType& type,
581586
LocationSummary* locs) {
582587
ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
583-
ASSERT(!type.IsObjectType() && !type.IsDynamicType() && !type.IsVoidType());
588+
ASSERT(!type.IsObjectType() && !type.IsDynamicType());
584589

585590
__ pushl(EDX); // Store instantiator type arguments.
586591
__ pushl(ECX); // Store function type arguments.
@@ -661,8 +666,7 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
661666
ASSERT(dst_type.IsFinalized());
662667
// Assignable check is skipped in FlowGraphBuilder, not here.
663668
ASSERT(dst_type.IsMalformedOrMalbounded() ||
664-
(!dst_type.IsDynamicType() && !dst_type.IsObjectType() &&
665-
!dst_type.IsVoidType()));
669+
(!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
666670
__ pushl(EDX); // Store instantiator type arguments.
667671
__ pushl(ECX); // Store function type arguments.
668672
// A null object is always assignable and is returned as result.

runtime/vm/flow_graph_compiler_mips.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,11 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
520520
Label* is_instance_lbl,
521521
Label* is_not_instance_lbl) {
522522
__ Comment("InlineInstanceof");
523+
if (type.IsVoidType()) {
524+
// A non-null value is returned from a void function, which will result in a
525+
// type error. A null value is handled prior to executing this inline code.
526+
return SubtypeTestCache::null();
527+
}
523528
if (type.IsInstantiated()) {
524529
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
525530
// A class equality check is only applicable with a dst type (not a
@@ -562,7 +567,7 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
562567
const AbstractType& type,
563568
LocationSummary* locs) {
564569
ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded());
565-
ASSERT(!type.IsObjectType() && !type.IsDynamicType() && !type.IsVoidType());
570+
ASSERT(!type.IsObjectType() && !type.IsDynamicType());
566571

567572
// Preserve instantiator type arguments (A1) and function type arguments (A2).
568573
__ addiu(SP, SP, Immediate(-2 * kWordSize));
@@ -648,8 +653,7 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
648653
ASSERT(dst_type.IsFinalized());
649654
// Assignable check is skipped in FlowGraphBuilder, not here.
650655
ASSERT(dst_type.IsMalformedOrMalbounded() ||
651-
(!dst_type.IsDynamicType() && !dst_type.IsObjectType() &&
652-
!dst_type.IsVoidType()));
656+
(!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
653657

654658
// Preserve instantiator type arguments (A1) and function type arguments (A2).
655659
__ addiu(SP, SP, Immediate(-2 * kWordSize));

runtime/vm/flow_graph_compiler_x64.cc

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,11 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
533533
Label* is_instance_lbl,
534534
Label* is_not_instance_lbl) {
535535
__ Comment("InlineInstanceof");
536+
if (type.IsVoidType()) {
537+
// A non-null value is returned from a void function, which will result in a
538+
// type error. A null value is handled prior to executing this inline code.
539+
return SubtypeTestCache::null();
540+
}
536541
if (type.IsInstantiated()) {
537542
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
538543
// A class equality check is only applicable with a dst type (not a
@@ -575,7 +580,7 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
575580
const AbstractType& type,
576581
LocationSummary* locs) {
577582
ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
578-
ASSERT(!type.IsObjectType() && !type.IsDynamicType() && !type.IsVoidType());
583+
ASSERT(!type.IsObjectType() && !type.IsDynamicType());
579584

580585
__ pushq(RDX); // Store instantiator type arguments.
581586
__ pushq(RCX); // Store function type arguments.
@@ -584,8 +589,8 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
584589
// If type is instantiated and non-parameterized, we can inline code
585590
// checking whether the tested instance is a Smi.
586591
if (type.IsInstantiated()) {
587-
// A null object is only an instance of Null, Object, void and dynamic.
588-
// Object void and dynamic have already been checked above (if the type is
592+
// A null object is only an instance of Null, Object, and dynamic.
593+
// Object and dynamic have already been checked above (if the type is
589594
// instantiated). So we can return false here if the instance is null,
590595
// unless the type is Null (and if the type is instantiated).
591596
// We can only inline this null check if the type is instantiated at compile
@@ -654,8 +659,7 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
654659
ASSERT(dst_type.IsFinalized());
655660
// Assignable check is skipped in FlowGraphBuilder, not here.
656661
ASSERT(dst_type.IsMalformedOrMalbounded() ||
657-
(!dst_type.IsDynamicType() && !dst_type.IsObjectType() &&
658-
!dst_type.IsVoidType()));
662+
(!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
659663
__ pushq(RDX); // Store instantiator type arguments.
660664
__ pushq(RCX); // Store function type arguments.
661665
// A null object is always assignable and is returned as result.

runtime/vm/flow_graph_type_propagator.cc

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ intptr_t CompileType::ToNullableCid() {
597597
} else if (type_->IsMalformed()) {
598598
cid_ = kDynamicCid;
599599
} else if (type_->IsVoidType()) {
600-
cid_ = kDynamicCid;
600+
cid_ = kNullCid;
601601
} else if (type_->IsFunctionType() || type_->IsDartFunctionType()) {
602602
cid_ = kClosureCid;
603603
} else if (type_->HasResolvedTypeClass()) {
@@ -684,7 +684,7 @@ bool CompileType::CanComputeIsInstanceOf(const AbstractType& type,
684684
return false;
685685
}
686686

687-
if (type.IsDynamicType() || type.IsObjectType() || type.IsVoidType()) {
687+
if (type.IsDynamicType() || type.IsObjectType()) {
688688
*is_instance = true;
689689
return true;
690690
}
@@ -696,6 +696,11 @@ bool CompileType::CanComputeIsInstanceOf(const AbstractType& type,
696696
// Consider the compile type of the value.
697697
const AbstractType& compile_type = *ToAbstractType();
698698

699+
// The compile-type of a value should never be void. The result of a void
700+
// function must always be null, which was checked to be null at the return
701+
// statement inside the function.
702+
ASSERT(!compile_type.IsVoidType());
703+
699704
if (compile_type.IsMalformedOrMalbounded()) {
700705
return false;
701706
}
@@ -710,6 +715,12 @@ bool CompileType::CanComputeIsInstanceOf(const AbstractType& type,
710715
return true;
711716
}
712717

718+
// A non-null value is not an instance of void.
719+
if (type.IsVoidType()) {
720+
*is_instance = IsNull();
721+
return HasDecidableNullability();
722+
}
723+
713724
// If the value can be null then we can't eliminate the
714725
// check unless null is allowed.
715726
if (is_nullable_ && !is_nullable) {
@@ -726,6 +737,11 @@ bool CompileType::IsMoreSpecificThan(const AbstractType& other) {
726737
return false;
727738
}
728739

740+
if (other.IsVoidType()) {
741+
// The only value assignable to void is null.
742+
return IsNull();
743+
}
744+
729745
return ToAbstractType()->IsMoreSpecificThan(other, NULL, NULL, Heap::kOld);
730746
}
731747

@@ -927,6 +943,11 @@ CompileType AssertAssignableInstr::ComputeType() const {
927943
return *value_type;
928944
}
929945

946+
if (dst_type().IsVoidType()) {
947+
// The only value assignable to void is null.
948+
return CompileType::Null();
949+
}
950+
930951
return CompileType::Create(value_type->ToCid(), dst_type());
931952
}
932953

@@ -1017,9 +1038,13 @@ CompileType StaticCallInstr::ComputeType() const {
10171038
}
10181039

10191040
if (Isolate::Current()->type_checks()) {
1041+
// Void functions are known to return null, which is checked at the return
1042+
// from the function.
10201043
const AbstractType& result_type =
10211044
AbstractType::ZoneHandle(function().result_type());
1022-
return CompileType::FromAbstractType(result_type);
1045+
return CompileType::FromAbstractType(
1046+
result_type.IsVoidType() ? AbstractType::ZoneHandle(Type::NullType())
1047+
: result_type);
10231048
}
10241049

10251050
return CompileType::Dynamic();

runtime/vm/object.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15825,7 +15825,7 @@ bool Instance::IsInstanceOf(
1582515825
ASSERT(!other.IsMalformed());
1582615826
ASSERT(!other.IsMalbounded());
1582715827
if (other.IsVoidType()) {
15828-
return true;
15828+
return false;
1582915829
}
1583015830
Zone* zone = Thread::Current()->zone();
1583115831
const Class& cls = Class::Handle(zone, clazz());

sdk/lib/_internal/js_runtime/lib/js_helper.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3415,6 +3415,11 @@ listSuperNativeTypeCast(value, property) {
34153415
propertyTypeCastError(value, property);
34163416
}
34173417

3418+
voidTypeCheck(value) {
3419+
if (value == null) return value;
3420+
throw new TypeErrorImplementation(value, 'void');
3421+
}
3422+
34183423
extractFunctionTypeObjectFrom(o) {
34193424
var interceptor = getInterceptor(o);
34203425
var signatureName = JS_GET_NAME(JsGetName.SIGNATURE_NAME);

tests/co19/co19-co19.status

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,3 @@ LibTest/math/cos_A01_t01: PASS, FAIL, OK # Issue 26261
6666
LibTest/math/tan_A01_t01: PASS, FAIL, OK # Issue 26261
6767
LibTest/math/log_A01_t01: PASS, FAIL, OK # Issue 26261
6868

69-
[ $compiler != dart2analyzer && $checked ]
70-
# Tests that fail on every runtime in checked mode, but not on the analyzer.
71-
Language/Functions/generator_return_type_t01: Fail # Co19 issue 110
72-
Language/Functions/generator_return_type_t02: Fail # Co19 issue 110
73-
Language/Functions/async_return_type_t01: Fail # Co19 issue 110
74-
Language/Types/Type_Void/returning_t02: Fail # Co19 issue 110
75-
Language/Types/Type_Void/returning_t03: Fail # Co19 issue 110
76-
Language/Types/Type_Void/returning_t04: Fail # Co19 issue 110
77-
Language/Types/Type_Void/returning_t05: Fail # Co19 issue 110

tests/language/return_type_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ void returnString2() => 's';
2121
main() {
2222
if (isCheckedMode()) {
2323
Expect.throws(returnString1, (e) => e is TypeError);
24-
returnString2();
24+
Expect.throws(returnString2, (e) => e is TypeError);
2525
returnNull();
2626
} else {
2727
returnString1();

0 commit comments

Comments
 (0)