Adobe-Runtime-Support icon indicating copy to clipboard operation
Adobe-Runtime-Support copied to clipboard

Implicit coercion error using Vectors with different data types casting

Open itlancer opened this issue 3 years ago • 16 comments

Problem Description

Implicit coercion error using Vectors with different data types casting. Sometimes you need to cast Vector.<Sprite> to Vector.<Object> (superclass data type) or even Vector.<*>. Vector data types are compatible but anyway you will get compile error (when strict mode enabled) or run-time (with disabled strict mode).

Tested with latest multiple AIR versions, even with latest AIR 33.1.1.476. Same problem in all cases.

This issue cause we need to use not ideal architectural solutions with worse performance to avoid this.

Steps to Reproduce

Compile and launch code below.

Application example with sources attached. vector_cast_bug.zip

package  {
	import flash.display.Sprite;
	
	public class VectorCastBug extends Sprite {
		
		public function VectorCastBug() {
			var vector:Vector.<uint> = new Vector.<uint>();
			vectorFunction(vector);//Type Coercion failed here
		}
		
		private function vectorFunction(vector:Vector.<*>):void {
			//Here suppose you can do something with vector
		}
	}
}

Actual Result: If strict mode for compiler enabled then you will get compile-time error: 1067: Implicit coercion of a value of type __AS3__.vec:Vector.<uint> to an unrelated type __AS3__.vec:Vector.<*>.

If strict mode for compiler disabled then you will get runtime-time error: TypeError: Error #1034: Type Coercion failed: cannot convert Vector.<uint>@6a47161 to __AS3__.vec.Vector.<*>.

Expected Result: Vector.<uint> will be correctly casted to Vector.<*> without errors.

Known Workarounds

Change function parameter to * and cast data type inside function:

private function vectorFunction(vector:*):void {
	var v:Vector.<*> = vector as Vector.<*>;
	//Here suppose you can do something with vector
}

itlancer avatar Jun 08 '21 20:06 itlancer

Well one of the team has just updated the AS3 compiler to allow the appropriate casting, but we need to look into the runtime aspects of this to see how possible it's going to be to work out the coercion at runtime...

ajwfrost avatar Jun 29 '21 13:06 ajwfrost

... okay that's easy enough. Coercion just means "complain if the types aren't related" -> so we can check the parameterised types and confirm that they're compatible. The vector can then be used and assignment of the objects within it will be subject to later checks, where of course it's still valid.

So this will be fixed in the next SDK release...

ajwfrost avatar Jun 30 '21 15:06 ajwfrost

@ajwfrost At AIR 33.1.1.554 Release Notes I can see at "Bug Fixes":

Github-894: Updating avmplus to allow coercion between Vectors of related types

But it still cause errors and doesn't work.

itlancer avatar Jul 14 '21 10:07 itlancer

This is working for us... what are you seeing? Compile-time problem, or run-time? We've been using:

var sprites : Vector.<MovieClip> = new Vector.<MovieClip>();

and add a MovieClip object, then call a function:

private function colourSprites(sprites : Vector.<Sprite>) : void

which then draws to the movieclip..

ajwfrost avatar Jul 14 '21 12:07 ajwfrost

@ajwfrost I made more tests with latest AIR 33.1.1.554 with different devices, IDEs and samples.

With MovieClip/Sprite coercion with compiler "strict mode" enabled it doesn't work. It throws compile-time error: 1067: Implicit coercion of a value of type __AS3__.vec:Vector.<flash.display:MovieClip> to an unrelated type __AS3__.vec:Vector.<flash.display:Sprite>.

With MovieClip/Sprite coercion with compiler "strict mode" disabled it works fine. With earlier AIR versions it throws run-time error.

With original issue uint/* coercion it still doesn't work. You can use attached sample at first post to reproduce this issue. Changing "strict mode" doesn't help - only depends you'll get compile-time or run-time error. The same problem with "uint to int" coercion etc.

itlancer avatar Jul 14 '21 14:07 itlancer

For the compilation - I'm using strict mode and it's okay.. are you definitely using the new compiler rather than a compiler from the Flex SDK?

Run-time: yes, Vector, Vector, Vector<*> etc are treated as special cases and so wouldn't work for this. But I think we have a way to detect these and check, without impacting things too much.

thanks

ajwfrost avatar Jul 14 '21 15:07 ajwfrost

@ajwfrost More tests :) All with new ActionScript Compiler, no Flex SDK.

  1. Command line usage (adl, adl64, adt, mxmlc and amxmlc) Indeed no compile errors. Sample application packaging also works fine without errors.

  2. Adobe Animate Compile errors when trying to launch (compile) for test or package application.

  3. FlashDevelop Compile errors when trying to launch (compile) for test.

  4. Visual Studio Code IDE shows such coercions as errors. image But launching works fine without errors.

May be something should be fixed with IDEs too?

itlancer avatar Jul 14 '21 17:07 itlancer

We can look into the IDEs; I've got it working in Flash Develop having updated my SDK list so that I'm using the newer path for the updated SDK. I suspect for all of them, they're set up to use a particular path to the compiler and it would need to be set to specifically use the appropriate value; if any of them are using Flex then it would need an update to the Flex compiler by the Apache team..

Then in terms of the various coercions needed here: Vector.<*> is treated as an 'Object' type, so it's possible to convert from Vector.<MovieClip> to Vector.<*> following our initial change. But Vector.<int> and all those are actually represented internally by different structures (more efficient as they don't include any reference counting/gc overheads). And when the JIT code runs, it sees e.g. the parameters of a function using Vector.<*> and therefore the element is just treated natively like this (ObjectVectorObject) type. As soon as you triied to access anything from it (if we allowed the coercion), we get a failure i.e. deliberate crash, as the runtime thinks that something's gone wrong with the memory.

So, it will not be possible to have automatic coercion from Vector.<int> etc to Vector.<*>.

But, you can do this fairly easily by wrapping up the conversion in the Vector() function, so where this will fail to run:

private function processAnyVector(vec : Vector.<*>) : void { trace(vec.length); }
var myVec : Vector.<uint> = new Vector.<uint>();
myVec.push(1, 2, 3);
processAnyVector(myVec);

you can actually get this to work by calling it as:

processAnyVector(Vector.<*>(myVec));

At this point, I'm thinking we perhaps should update the compiler so that the first form here (i.e. trying to get it to do the coercion) will fail at compile-time rather than run-time i.e. enforce the second form which is something that will then work at run-time....

ajwfrost avatar Jul 15 '21 09:07 ajwfrost

Thanks! Meanwhile I try to look what's going on with FlashDevelop. May be SDK link didn't updated properly...

itlancer avatar Jul 15 '21 09:07 itlancer

https://forum.starling-framework.org/d/23104-air-3311-build-554-typed-vector-loses-its-generic-type same issue

shaymolho avatar Aug 01 '21 10:08 shaymolho

Thanks @shaymolho - just to add the information here, the bug linked above is because our change to allow casting/coercion has caused a change in behaviour if you're using the Vector() function in order to do a copy to a different type... We'll need to investigate this to see how we can make the compile explicitly call the Vector() function still if it's written in the, rather than allowing an implicit coercion.

So for example if you have a Vector.<MovieClip> object called 'myMCs' that contains 5 MovieClip objects:

var copyOfVector : Vector.<Sprite> = myMCs; // would have failed prior to 554: now it should allow this to treat copyOfVector as just another reference to the same `Vector.<MovieClip>` object
var newVector : Vector.<Sprite> = Vector.<Sprite>(myMCs); // works but prior to 554 would give a new vector of references to the MCs as sprites; now it just references the existing myMCs object
// the difference being:
myMCs.length = 0;
trace(copyOfVector.length); // invalid prior to 554: now returns 0
trace(newVector); // prior to 554 would be 5 still; now returns 0

Looking at this I'm actually wondering what happens if you had copyOfVector in the above example, and tried adding a new Sprite to it... I suspect it would throw a runtime exception because you may think you have a reference to a Vector.<Sprite>, but the underlying object is still a Vector.<MovieClip>....

@itlancer would be interested in your thoughts here, whether there are behaviours that make more sense when we're having a reference that contains different types. I'm wondering whether actually, the simpler thing would have been to remove the need for the Vector() function but to keep that sort of behaviour i.e. move to a scenario where:

var copyOfVector : Vector.<Sprite> = myMCs; // now would just have the same behaviour as:
var newVector : Vector.<Sprite> = Vector.<Sprite>(myMCs); // i.e. gives a new vector of references to the MCs as sprites

(Slight disclaimer = I'm writing all the above without having actually tried these out to see if I'm right, but just going from memory of how the code works... but we'll check on this and if we see any differences, I'll update this...)

ajwfrost avatar Aug 01 '21 20:08 ajwfrost

@ajwfrost my opinion that var newVector : Vector.<Sprite> = Vector.<Sprite>(myMCs); should give a new vector of references to the MCs as sprites cause we use explicit coercion by Vector().

But about var copyOfVector : Vector.<Sprite> = myMCs; I don't know "correct" solution. We didn't use such approach. So if it will also gives new vector of references to the MCs as sprites - that will be ok I think.

itlancer avatar Aug 02 '21 11:08 itlancer

Copying into in from the Starling forum:

Bit of a delay here, sorry, but we'll have this resolved in the next release of the AIR SDK. It looks like we've been able to keep the new coercion to related Vector types whilst ensuring that the old behaviour is unchanged.

Interestingly .. if you have an object var original : Vector.<Sprite> and you do var newObj : Vector.<Sprite> = Vector.<Sprite>(original); then the Vector function doesn't actually have any effect, and no new object is created? i.e. newObj and original both point to the same underlying vector object. Seemed a little odd but that's what was happening..

So, now: If you have var vecMC : Vector.<MovieClip> then you can do var vecS : Vector.<Sprite> = vecMC and this will work in terms of the coercion, but will not create a new object. So you can only add other MovieClips to vecS. But if you do var vecS : Vector.<Sprite> = Vector.<Sprite>(vecMC) then you get a new vector where you can only add other Sprites: it is populated with the original movieclips from vecMC but it's now independent in terms of the vector object.

Hopefully that will satisfy everyone :-)

thanks

ajwfrost avatar Aug 27 '21 15:08 ajwfrost

@ajwfrost With latest AIR SDK 33.1.1.620 for me all tests with coercion give the same result as described earlier: https://github.com/airsdk/Adobe-Runtime-Support/issues/894#issuecomment-880065567

  1. Command line usage (adl, adl64, adt, mxmlc and amxmlc) No compile errors. All fine.

  2. Adobe Animate Compile errors when trying to launch (compile) for test or package application using strict mode. All works fine when strict mode disabled.

  3. Visual Studio Code IDE shows such coercions as errors. image But application launching works fine without errors.

How to avoid Visual Studio code "errors" and make Animate work with strict mode?

itlancer avatar Sep 20 '21 16:09 itlancer

Yes in terms of the compiler, we didn't change anything, it was just the runtime implementation that needed to update to give it that behaviour.

Which means, we need to try to see why Animate/VSCode are seeing these as problems. I suspect there will be some other library/specification that they are using to review the code to see why it may be happening (or, they are perhaps using a different compiler class....) - we can check on that...

ajwfrost avatar Sep 20 '21 17:09 ajwfrost

Issue still exists for Animate and VSCode with latest AIR 51.0.0.3.

itlancer avatar Mar 20 '24 15:03 itlancer