Skip to content
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

@:structInit on forwarded abstracts breaks when using @:from another structInit type #11535

Closed
nspitko opened this issue Feb 2, 2024 · 5 comments

Comments

@nspitko
Copy link

nspitko commented Feb 2, 2024

One thing I've been doing in my codebase is using forwarded abstract types over structInit classes. This enabled some neat trickery, like a vector class that can seamlessly convert between several other vector classes from other libs, as well as inline itself when possible, saving on allocs.

However, I noticed recently that if you @:from against another @:structInit type, you somehow lose the ability to initialize with struct syntax.

In the demo below, the code will fail to compile unless we remove the @:structInit tagging from BarImpl

// Bar 
// Removing this @:structInit will fix the build.
@:structInit
class BarImpl {
	public function new() {}
}

// FooImpl
@:structInit
class FooImpl {
	public var x:Float;

	public function new(x:Float) {
		this.x = x;
	}
}

// Foo
@:forward
abstract Foo(FooImpl) from FooImpl to FooImpl {
	public function new(x:Float) {
		this = new FooImpl(x);
	}

	@:from
	static public function fromVec4(v:BarImpl):Foo {
		return new Foo(1);
	}
}

// Main
class Test {
	static function main() {
		var v:Foo = {x: 2};
		trace(v.x);
	}
}

Try.haxe: https://try.haxe.org/#cB1428eD

@nspitko nspitko changed the title @:structInit on forwarded abstracts breaks when using @:to/from another structInit type @:structInit on forwarded abstracts breaks when using @:from another structInit type Feb 2, 2024
@Simn
Copy link
Member

Simn commented Feb 2, 2024

That looks a bit painful... What probably happens is that the compiler refuses to top-down infer because of multiple choices (from FooImpl and @:from BarImpl). If there's only one @:structInit then it knows to use that, but once there are multiple this isn't going to work.

@kLabz
Copy link
Contributor

kLabz commented Feb 2, 2024

Foo not working there while Bar does makes me think we can do something about it:
https://try.haxe.org/#E9aa7d01

@Simn
Copy link
Member

Simn commented Feb 2, 2024

That's a different case which doesn't even involve @:structInit, and simply works because you can assign the {x: 2.0} to the fromVec4 argument. The significant problem with @:structInit that it needs top-down inference by-design, and the compiler rejects top-down inference if there's multiple choices.

@nspitko
Copy link
Author

nspitko commented Feb 2, 2024

In my case at least, I wouldn't have expected @:structInit initializers to work through @:from types, so I'd be perfectly OK with the compiler just only accepting the forwarded type's option.

@Simn
Copy link
Member

Simn commented Feb 3, 2024

We had a similar problem before and allowed @:from(ignoredByInference) to deal with it. That isn't specific to @:structInit though, so I don't know if it's a good general solution.

Perhaps not allowing this at all would be better because going through both a @:structInit and @:from could be considered a transitive cast.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants