Skip to content

Variance 7.4 #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Zend/tests/bug76451.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php

class Foo {}
class_alias('Foo', 'Bar');
14 changes: 14 additions & 0 deletions Zend/tests/bug76451.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Aliases during inheritance type checks (affected by opcache)
--FILE--
<?php
require __DIR__ . "/bug76451.inc";

class A {
public function test(Foo $foo) {}
}
class B extends A {
public function test(Bar $foo) {}
}
?>
--EXPECT--
8 changes: 5 additions & 3 deletions Zend/tests/return_types/008.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class qux implements foo {
}

$qux = new qux();
var_dump($qux->bar());
--EXPECTF--
Fatal error: Declaration of qux::bar(): qux must be compatible with foo::bar(): foo in %s008.php on line 8
echo get_class($qux->bar());

?>
--EXPECT--
qux
8 changes: 5 additions & 3 deletions Zend/tests/return_types/generators003.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class SomeCollection implements Collection {
}

$some = new SomeCollection();
var_dump($some->getIterator());
--EXPECTF--
Fatal error: Declaration of SomeCollection::getIterator(): Generator must be compatible with Collection::getIterator(): Iterator in %sgenerators003.php on line 7
echo get_class($some->getIterator());

?>
--EXPECT--
Generator
8 changes: 6 additions & 2 deletions Zend/tests/return_types/inheritance005.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,9 @@ class Bar extends Foo {
return new Bar;
}
}
--EXPECTF--
Fatal error: Declaration of Bar::test(): Bar must be compatible with Foo::test(): Foo in %sinheritance005.php on line 9

echo get_class(Bar::test());

?>
--EXPECT--
Bar
8 changes: 6 additions & 2 deletions Zend/tests/return_types/inheritance006.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@ class Bar extends Foo {
return new B;
}
}
--EXPECTF--
Fatal error: Declaration of Bar::test(): B must be compatible with Foo::test(): A in %sinheritance006.php on line 11

echo get_class(Bar::test());

?>
--EXPECT--
B
8 changes: 6 additions & 2 deletions Zend/tests/return_types/inheritance007.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,9 @@ class Bar extends Foo {
return new ArrayObject([1, 2]);
}
}
--EXPECTF--
Fatal error: Declaration of Bar::test(): ArrayObject must be compatible with Foo::test(): Traversable in %sinheritance007.php on line 9

echo get_class(Bar::test());

?>
--EXPECT--
ArrayObject
28 changes: 28 additions & 0 deletions Zend/tests/type_declarations/variance/across_namespaces_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
Variance checks work across same-file namespaces (brace style)
--FILE--
<?php

namespace Foo {
class A {
function foo(B $x): A {
return new self();
}
}
}

namespace Bar {
class B extends \Foo\A {
function foo(\stdClass $x): B {
return new self();
}
}
}

namespace {
echo get_class((new \Bar\B())->foo(new \stdClass()));
}
?>
--EXPECTF--
Warning: Declaration of Bar\B::foo(stdClass $x): Bar\B should be compatible with Foo\A::foo(Foo\B $x): Foo\A in %s on line %d
Bar\B
26 changes: 26 additions & 0 deletions Zend/tests/type_declarations/variance/across_namespaces_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
Variance checks work across same-file namespaces
--FILE--
<?php

namespace Foo;

class A {
function foo(B $x): A {
return new self();
}
}

namespace Bar;

class B extends \Foo\A {
function foo(\stdClass $x): B {
return new self();
}
}

echo get_class((new \Bar\B())->foo(new \stdClass()));
?>
--EXPECTF--
Warning: Declaration of Bar\B::foo(stdClass $x): Bar\B should be compatible with Foo\A::foo(Foo\B $x): Foo\A in %s on line %d
Bar\B
23 changes: 23 additions & 0 deletions Zend/tests/type_declarations/variance/conditional_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
Delayed variance checks work with conditional statements
--FILE--
<?php

interface A {
static function m(Y $z): A;
}

if (true) {
class B implements A {
static function m(X $z): B {
return new self();
}
}
class X {}
class Y extends X {}
}

echo get_class(B::m(new X()));
?>
--EXPECTF--
B
23 changes: 23 additions & 0 deletions Zend/tests/type_declarations/variance/conditional_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
Delayed variance checks work with conditional statements
--FILE--
<?php

interface A {
static function m(Y $z): A;
}

if (true) {
class B implements A {
static function m(X $z): B {
return new self();
}
}
class X {}
//class Y extends X {}
}

echo get_class(B::m(new X()));
?>
--EXPECTF--
Fatal error: Declaration of B::m(X $z): B must be compatible with A::m(Y $z): A in %s on line %d
26 changes: 26 additions & 0 deletions Zend/tests/type_declarations/variance/enum_forward_compat.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
Forward compatibility with types that look like classes but aren't
--FILE--
<?php

spl_autoload_register(function($class) {
var_dump($class);
if ($class === 'X') {
class X {}
} else {
class Y {}
}
});

class A {
public function method(X $param) : object {}
}

class B extends A {
public function method(object $param) : Y {}
}

?>
--EXPECT--
string(1) "X"
string(1) "Y"
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
non-consecutive type decls are still checked for variance
--FILE--
<?php

interface A {
function m(): A;
}

// "echo 'hi';" is not a declaration statement
echo 'hi';

class B implements A {
function m(): B { return $this; }
}

echo get_class((new B())->m());
?>
--EXPECT--
hiB
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
non-consecutive type decls are still checked for variance
--FILE--
<?php

interface A {
function m(): A;
}

// "echo 'hi';" is not a declaration statement
echo 'hi';

class B implements A {
function m(): stdClass { return $this; }
}

echo get_class((new B())->m());
?>
--EXPECTF--
hi
Fatal error: Declaration of B::m(): stdClass must be compatible with A::m(): A in %s on line %d
22 changes: 22 additions & 0 deletions Zend/tests/type_declarations/variance/object_variance.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Testing object's variance in inheritance
--FILE--
<?php

interface I1 {
function method1(I1 $o): object;
}
interface I2 extends I1 {
function method1(object $o): I1;
}
final class C1 implements I2 {
function method1($o = null): self {
return $this;
}
}

$o = new C1();
echo get_class($o->method1());
?>
--EXPECT--
C1
45 changes: 45 additions & 0 deletions Zend/tests/type_declarations/variance/parent_in_class.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
--TEST--
Use of parent inside a class that has / has no parent
--FILE--
<?php

// Illegal: A::parent is ill-defined
class A {
public function method(parent $x) {}
}
class B extends A {
public function method(parent $x) {}
}

// Legal: A2::parent == P2
class P2 {}
class A2 extends P2 {
public function method(parent $x) {}
}
class B2 extends A2 {
public function method(P2 $x) {}
}

// Legal: B3::parent == A3 is subclass of A3::parent == P3 in covariant position
class P3 {}
class A3 extends P3 {
public function method($x): parent {}
}
class B3 extends A3 {
public function method($x): parent {}
}

// Illegal: B4::parent == A4 is subclass of A4::parent == P4 in contravariant position
class P4 {}
class A4 extends P4 {
public function method(parent $x) {}
}
class B4 extends A4 {
public function method(parent $x) {}
}

?>
--EXPECTF--
Warning: Declaration of B::method(A $x) should be compatible with A::method(parent $x) in %s on line 8

Warning: Declaration of B4::method(A4 $x) should be compatible with A4::method(P4 $x) in %s on line 35
19 changes: 19 additions & 0 deletions Zend/tests/type_declarations/variance/parent_in_trait.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
Trait using parent used inside class without parent
--FILE--
<?php

trait T {
function foo(parent $x) {}
}

class A {
use T;
}
class B extends A {
function foo(parent $x) {}
}

?>
--EXPECTF--
Warning: Declaration of B::foo(A $x) should be compatible with A::foo(parent $x) in %s on line %d
20 changes: 20 additions & 0 deletions Zend/tests/type_declarations/variance/runtime_fail.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
Classes do not exist at compile-time and have incorrect variance at runtime
--FILE--
<?php

if (true) {
class X {}
class Y {}
}

class A {
public function method(): X {}
}
class B extends A {
public function method(): Y {}
}

?>
--EXPECTF--
Fatal error: Declaration of B::method(): Y must be compatible with A::method(): X in %s on line 12
15 changes: 15 additions & 0 deletions Zend/tests/type_declarations/variance/undefined_type_01.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Undefined types during variance checks are warnings
--FILE--
<?php

class X {
function m(stdClass $z) {}
}

class Y extends X {
function m(UndefinedA $z) {}
}
?>
--EXPECTF--
Warning: Declaration of Y::m(UndefinedA $z) should be compatible with X::m(stdClass $z) in %s on line %d
15 changes: 15 additions & 0 deletions Zend/tests/type_declarations/variance/undefined_type_02.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Undefined types during variance checks are warnings
--FILE--
<?php

abstract class X {
function m(stdClass $z) {}
}

class Y extends X {
function m(UndefinedA $z) {}
}
?>
--EXPECTF--
Warning: Declaration of Y::m(UndefinedA $z) should be compatible with X::m(stdClass $z) in %s on line %d
Loading