Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 493705

Summary: org.eclipse.jdt.internal.compiler.ast.LambdaExpression$CopyFailureException
Product: [Eclipse Project] JDT Reporter: Erdal Karaca <erdal.karaca.de>
Component: CoreAssignee: Sasikanth Bharadwaj <sasikanth.bharadwaj>
Status: VERIFIED FIXED QA Contact:
Severity: major    
Priority: P3 CC: jarthana, manoj.palat, markus.kell.r, mlippert, sasikanth.bharadwaj, stephan.herrmann
Version: 3.1   
Target Milestone: 4.7 M7   
Hardware: PC   
OS: Windows 10   
See Also: https://git.eclipse.org/r/73460
https://bugs.eclipse.org/bugs/show_bug.cgi?id=460921
https://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=30b8634488c2a308787d6f4bc05e881c37e80405
Whiteboard:

Description Erdal Karaca CLA 2016-05-15 08:42:57 EDT
This is the code that triggers the exception. See comment for details on how to reproduce.

		root.layout(GridLayoutFactory.swtDefaults().numColumns(2).create())//
				.child(() -> SwtUI.create(Label::new)// <-- insert DOT here and
														// the exception occurs
		);


-- Error Details --
Date: Sun May 15 14:13:19 CEST 2016
Message: The 'org.eclipse.jdt.ui.JavaAllCompletionProposalComputer' proposal computer from the 'org.eclipse.jdt.ui' plug-in did not complete normally. The extension has thrown a runtime exception.
Severity: Warning
Product: Eclipse 4.5.2.20160218-0600 (org.eclipse.epp.package.modeling.product)
Plugin: org.eclipse.jdt.ui
Session Data:
eclipse.buildId=4.5.2.M20160212-1500
java.version=1.8.0_91
java.vendor=Oracle Corporation
BootLoader constants: OS=win32, ARCH=x86_64, WS=win32, NL=de_DE
Framework arguments:  -product org.eclipse.epp.package.modeling.product
Command-line arguments:  -os win32 -ws win32 -arch x86_64 -product org.eclipse.epp.package.modeling.product

Exception Stack Trace:
org.eclipse.jdt.internal.compiler.ast.LambdaExpression$CopyFailureException
	at org.eclipse.jdt.internal.compiler.ast.LambdaExpression.cachedResolvedCopy(LambdaExpression.java:853)
	at org.eclipse.jdt.internal.compiler.ast.LambdaExpression.sIsMoreSpecific(LambdaExpression.java:925)
	at org.eclipse.jdt.internal.compiler.lookup.InferenceContext18.moreSpecificMain(InferenceContext18.java:686)
	at org.eclipse.jdt.internal.compiler.lookup.InferenceContext18.isMoreSpecificThan(InferenceContext18.java:662)
	at org.eclipse.jdt.internal.compiler.lookup.Scope.mostSpecificMethodBinding(Scope.java:4324)
	at org.eclipse.jdt.internal.compiler.lookup.Scope.findDefaultAbstractMethod(Scope.java:1176)
	at org.eclipse.jdt.internal.compiler.lookup.Scope.findMethod0(Scope.java:1809)
	at org.eclipse.jdt.internal.compiler.lookup.Scope.findMethod(Scope.java:1546)
	at org.eclipse.jdt.internal.compiler.lookup.Scope.getMethod(Scope.java:2822)
	at org.eclipse.jdt.internal.compiler.ast.MessageSend.findMethodBinding(MessageSend.java:898)
	at org.eclipse.jdt.internal.compiler.ast.MessageSend.resolveType(MessageSend.java:712)
	at org.eclipse.jdt.internal.compiler.ast.Expression.resolve(Expression.java:1020)
	at org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.resolveStatements(AbstractMethodDeclaration.java:641)
	at org.eclipse.jdt.internal.compiler.ast.MethodDeclaration.resolveStatements(MethodDeclaration.java:309)
	at org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.resolve(AbstractMethodDeclaration.java:551)
	at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.resolve(TypeDeclaration.java:1188)
	at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.resolve(TypeDeclaration.java:1301)
	at org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration.resolve(CompilationUnitDeclaration.java:590)
	at org.eclipse.jdt.internal.codeassist.CompletionEngine.complete(CompletionEngine.java:1923)
	at org.eclipse.jdt.internal.core.Openable.codeComplete(Openable.java:131)
	at org.eclipse.jdt.internal.core.CompilationUnit.codeComplete(CompilationUnit.java:357)
	at org.eclipse.jdt.internal.core.CompilationUnit.codeComplete(CompilationUnit.java:345)
	at org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposalComputer.internalComputeCompletionProposals(JavaCompletionProposalComputer.java:244)
	at org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposalComputer.computeCompletionProposals(JavaCompletionProposalComputer.java:206)
	at org.eclipse.jdt.internal.ui.text.java.JavaTypeCompletionProposalComputer.computeCompletionProposals(JavaTypeCompletionProposalComputer.java:63)
	at org.eclipse.jdt.internal.ui.text.java.CompletionProposalComputerDescriptor.computeCompletionProposals(CompletionProposalComputerDescriptor.java:333)
	at org.eclipse.jdt.internal.ui.text.java.CompletionProposalCategory.computeCompletionProposals(CompletionProposalCategory.java:337)
	at org.eclipse.jdt.internal.ui.text.java.ContentAssistProcessor.collectProposals(ContentAssistProcessor.java:322)
	at org.eclipse.jdt.internal.ui.text.java.ContentAssistProcessor.computeCompletionProposals(ContentAssistProcessor.java:279)
	at org.eclipse.jface.text.contentassist.ContentAssistant$5.run(ContentAssistant.java:1904)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.jface.text.contentassist.ContentAssistant.computeCompletionProposals(ContentAssistant.java:1902)
	at org.eclipse.jface.text.contentassist.CompletionProposalPopup.computeProposals(CompletionProposalPopup.java:573)
	at org.eclipse.jface.text.contentassist.CompletionProposalPopup.access$16(CompletionProposalPopup.java:570)
	at org.eclipse.jface.text.contentassist.CompletionProposalPopup$2.run(CompletionProposalPopup.java:505)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
	at org.eclipse.jface.text.contentassist.CompletionProposalPopup.showProposals(CompletionProposalPopup.java:499)
	at org.eclipse.jface.text.contentassist.ContentAssistant.showPossibleCompletions(ContentAssistant.java:1720)
	at org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor$AdaptedSourceViewer.doOperation(CompilationUnitEditor.java:180)
	at org.eclipse.ui.texteditor.ContentAssistAction$1.run(ContentAssistAction.java:82)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
	at org.eclipse.ui.texteditor.ContentAssistAction.run(ContentAssistAction.java:80)
	at org.eclipse.jface.action.Action.runWithEvent(Action.java:473)
	at org.eclipse.jface.commands.ActionHandler.execute(ActionHandler.java:122)
	at org.eclipse.ui.internal.handlers.E4HandlerProxy.execute(E4HandlerProxy.java:90)
	at sun.reflect.GeneratedMethodAccessor54.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:56)
	at org.eclipse.e4.core.internal.di.InjectorImpl.invokeUsingClass(InjectorImpl.java:252)
	at org.eclipse.e4.core.internal.di.InjectorImpl.invoke(InjectorImpl.java:234)
	at org.eclipse.e4.core.contexts.ContextInjectionFactory.invoke(ContextInjectionFactory.java:132)
	at org.eclipse.e4.core.commands.internal.HandlerServiceHandler.execute(HandlerServiceHandler.java:152)
	at org.eclipse.core.commands.Command.executeWithChecks(Command.java:493)
	at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:486)
	at org.eclipse.e4.core.commands.internal.HandlerServiceImpl.executeHandler(HandlerServiceImpl.java:210)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.executeCommand(KeyBindingDispatcher.java:286)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.press(KeyBindingDispatcher.java:507)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.processKeyEvent(KeyBindingDispatcher.java:558)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.filterKeySequenceBindings(KeyBindingDispatcher.java:378)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.access$0(KeyBindingDispatcher.java:324)
	at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher$KeyDownFilter.handleEvent(KeyBindingDispatcher.java:86)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Display.filterEvent(Display.java:1266)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1112)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1137)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1122)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1164)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1160)
	at org.eclipse.swt.widgets.Widget.wmChar(Widget.java:1581)
	at org.eclipse.swt.widgets.Control.WM_CHAR(Control.java:4795)
	at org.eclipse.swt.widgets.Canvas.WM_CHAR(Canvas.java:343)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:4676)
	at org.eclipse.swt.widgets.Canvas.windowProc(Canvas.java:339)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:5050)
	at org.eclipse.swt.internal.win32.OS.DispatchMessageW(Native Method)
	at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:2549)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3767)
	at org.eclipse.jface.window.Window.runEventLoop(Window.java:827)
	at org.eclipse.jface.window.Window.open(Window.java:803)
	at org.eclipse.ui.internal.views.log.EventDetailsDialog.open(EventDetailsDialog.java:181)
	at org.eclipse.ui.internal.views.log.EventDetailsDialogAction.run(EventDetailsDialogAction.java:98)
	at org.eclipse.ui.internal.views.log.LogView$15.doubleClick(LogView.java:546)
	at org.eclipse.jface.viewers.StructuredViewer$1.run(StructuredViewer.java:832)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.ui.internal.JFaceUtil$1.run(JFaceUtil.java:50)
	at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:173)
	at org.eclipse.jface.viewers.StructuredViewer.fireDoubleClick(StructuredViewer.java:829)
	at org.eclipse.jface.viewers.AbstractTreeViewer.handleDoubleSelect(AbstractTreeViewer.java:1470)
	at org.eclipse.jface.viewers.StructuredViewer$4.widgetDefaultSelected(StructuredViewer.java:1263)
	at org.eclipse.jface.util.OpenStrategy.fireDefaultSelectionEvent(OpenStrategy.java:252)
	at org.eclipse.jface.util.OpenStrategy.access$0(OpenStrategy.java:249)
	at org.eclipse.jface.util.OpenStrategy$1.handleEvent(OpenStrategy.java:311)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4362)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1113)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4180)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3769)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$4.run(PartRenderingEngine.java:1127)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:337)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1018)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:156)
	at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:694)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:337)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:606)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:150)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:139)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:380)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:235)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:669)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:608)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1515)
Comment 1 Jay Arthanareeswaran CLA 2016-05-16 07:02:01 EDT
Could you please provide a sample with the missing types? Thanks!
Comment 2 Erdal Karaca CLA 2016-05-17 07:54:01 EDT
I could not figure out what of my scenario/code causes this bug to extract a minimalistic example.
So, I hope it is fine for you to grab the following plugins from my github repo [1] (sources are EPL):


- de.metadocks.lambdaui
- de.metadocks.lambdaui.snippets

Once you have checked out the projects into your workspace, you can open, for example, the class de.metadocks.lambdaui.snippets.swt.HelloWorld and insert a dot at the end of line 77 (and wait for content assist to help, but fail here).

[1] https://github.com/erdalkaraca/lambda-ui/tree/master/plugins
Comment 3 Erdal Karaca CLA 2016-05-19 02:39:39 EDT
Jay,
Do you think this bug can still be fixed for Neon?
Comment 4 Jay Arthanareeswaran CLA 2016-05-24 02:59:35 EDT
(In reply to Erdal Karaca from comment #3)
> Jay,
> Do you think this bug can still be fixed for Neon?

I am afraid not. We will take a look at this during 4.7 and if possible back port to 4.6.1.
Comment 5 Stephan Herrmann CLA 2016-05-24 06:51:48 EDT
I gave it a first look, observations:

(In reply to Erdal Karaca from comment #2)
> ...
> insert a dot at the end of line 77 (and wait for content assist to help, but
> fail here).

A dot at the very end didn't trigger the bug for me, but this:
    .text("Selection).|)


At the point where we reparse the lambda, the scanner's toString() throws an exception, happens at:

	buffer.append("<source beginning>\n...\n"); //$NON-NLS-1$
	int line = Util.getLineNumber(this.startPosition-1000, this.lineEnds, 0, this.linePtr);
	int lineStart = getLineStart(line);
	buffer.append(this.source, lineStart, this.startPosition-lineStart);

Current values:
  line = 1
  lineStart = -1

This is a problem with lineEnds, which at that point are an int[250] filled with '0' from top to toe. Perhaps a result of "recordLineSeparators = false", but  this makes debugging painful without a working toString().

Rather than live inspection, this is what DEBUG=true prints during lambda reparse:

-- ENTER INSIDE PARSE METHOD --
NestedLambda ::=
PushLPAREN ::= LPAREN
FormalParameterListopt ::=
PushRPAREN ::= RPAREN
ElidedLeftBraceAndReturn ::=
Name ::= SimpleName
QualifiedName ::= Name DOT SimpleName
Name ::= SimpleName
Dimsopt ::=
NonWildTypeArgumentsopt ::=
IdentifierOrNew ::= new
ReferenceExpression ::= Name Dimsopt COLON_COLON...
Expression ::= AssignmentExpression
MethodInvocation ::= Name LPAREN ArgumentListopt RPAREN
Expression ::= AssignmentExpression
MethodInvocation ::= Primary DOT Identifier LPAREN...
-- EXIT FROM PARSE METHOD --

Doesn't look totally off the mark, but finally null is returned because of "this.lastAct == ERROR_ACTION".

Q: Isn't a syntax error to be expected during complete?

Experiment: set "this.haltOnSyntaxError = false" in parseLambdaExpression()
Result: parsing seems to restart at the top of the file, which is not what we want.


We hit ERROR_ACTION, when currentToken = TokenNameEOF, at a point with the following stack content:

astStack (lenght 1):
      LambdaExpression "() -> {}"
expressionStack (length 1): MessageSend
      SwtUI.create(Label::new).text("Selection")

All looks good, except that we haven't folded the expression into the lambda.
We can't yet do this, because the expression is not properly terminated (the final ')' is outside the range to parse).


So much for my observations trying to understand the CopyFailureException. Next in this theatre: isn't CopyFailureException actually expected during assist parsing?
Comment 6 Stephan Herrmann CLA 2016-05-24 07:17:19 EDT
OK, *normally* CopyFailureException during code assist is silently caught in LE.isCompatibleWith().

But in this example the exception is raised in a call chain from LE.sIsMoreSpecific()!

That's a useful cue (which also explains difficulty to isolate the problem in a smaller example).
Comment 7 Eclipse Genie CLA 2016-05-24 07:42:53 EDT
New Gerrit change created: https://git.eclipse.org/r/73460
Comment 8 Erdal Karaca CLA 2016-05-24 07:52:09 EDT
Thanks, Stephan!
It seems that you have also isolated a minimalistic example/test to reproduce.
Comment 9 Stephan Herrmann CLA 2016-05-24 08:02:51 EDT
(In reply to Erdal Karaca from comment #8)
> Thanks, Stephan!
> It seems that you have also isolated a minimalistic example/test to
> reproduce.

The key to this test case was to include these two methods from SwtUI:

	public SwtUI<T> child(ControlSupplier supplier)
	public SwtUI<T> child(ViewerSupplier supplier)

<lecture>
Aside from the completion issue, let me mention that this style of programming drives type inference to its limits (and perhaps beyond): overloading (the most convoluted concept in the Java language) combined with a difference in signatures of only two functional interfaces and then a lambda expression to make that choice with minimal type information contained, wow!

One lesson I learned from implementing this inference: I cannot explain why and when overload resolution works and which result it will pick, at least not in terms that are amenable to a developer's understanding of their own code.
For the sake of comprehensibility and predictability: use different names for those methods. It's so easy and avoids tremendous hassle.
</lecture>

Jay, Sassi,

if hudons gives +1 I'm fine with putting this in RC3, but I won't push hard on it...
Comment 10 Erdal Karaca CLA 2016-05-25 15:34:07 EDT
That was a solution driven by unconscious programming :-)

(In reply to Stephan Herrmann from comment #9)
> (In reply to Erdal Karaca from comment #8)
> > Thanks, Stephan!
> > It seems that you have also isolated a minimalistic example/test to
> > reproduce.
> 
> The key to this test case was to include these two methods from SwtUI:
> 
> 	public SwtUI<T> child(ControlSupplier supplier)
> 	public SwtUI<T> child(ViewerSupplier supplier)
> 
> <lecture>
> Aside from the completion issue, let me mention that this style of
> programming drives type inference to its limits (and perhaps beyond):
> overloading (the most convoluted concept in the Java language) combined with
> a difference in signatures of only two functional interfaces and then a
> lambda expression to make that choice with minimal type information
> contained, wow!
> 
> One lesson I learned from implementing this inference: I cannot explain why
> and when overload resolution works and which result it will pick, at least
> not in terms that are amenable to a developer's understanding of their own
> code.
> For the sake of comprehensibility and predictability: use different names
> for those methods. It's so easy and avoids tremendous hassle.
> </lecture>
> 
> Jay, Sassi,
> 
> if hudons gives +1 I'm fine with putting this in RC3, but I won't push hard
> on it...
Comment 11 Martin Lippert CLA 2017-02-28 06:48:01 EST
Any chance for this to make it into Neon.3 ?
Would be great to get the fix in.
Comment 12 Markus Keller CLA 2017-04-04 13:44:04 EDT
Had this as well in an incomplete SWT snippet:

	Image image= new Image(display, (int z) -> {
		ImageData imageData= new ImageData(IMAGE_WIDTH, IMAGE_HEIGHT, 24, new PaletteData(0xff, 0xff00, 0xff0000));
		imageData.setAlpha(, y1, 255);
		return imageData;
	});

Try to invoke Content Assist after "imageData.setAlpha(".


(In reply to Stephan Herrmann from comment #9)
> overloading (the most convoluted concept in the Java language) combined with
> a difference in signatures of only two functional interfaces and then a
> lambda expression to make that choice with minimal type information
> contained, wow!

Thanks for the reminder and your very insightful blogpost on this matter:
https://objectteams.wordpress.com/2017/04/02/several-languages-java-8/

Too bad Java's unnamed constructors sometimes make overloading hard to avoid.
Comment 13 Stephan Herrmann CLA 2017-04-04 16:39:15 EDT
(In reply to Markus Keller from comment #12)
> Too bad Java's unnamed constructors sometimes make overloading hard to avoid.

Let me add two quotes from Gilad's linked post "Systemic Overload":

- "Constructors are a bad idea, as I’ve already explained, so let’s assume we don’t have them."

- "Arity based overloading, as in e.g., Erlang, is pretty harmless."

Considering the latter, I could even see some sense in adding a parameter just to move from type based overloading to arity based. Consider naming the additional parameter(s) "int overloadKludge1" ... :)
Comment 14 Stephan Herrmann CLA 2017-04-09 09:17:01 EDT
@Sasi, we have a proposed patch. Bug is assigned to your name. Perhaps you just want to rebase & glance over the fix before pushing?
Comment 15 Sasikanth Bharadwaj CLA 2017-04-10 02:03:06 EDT
(In reply to comment #14)
> @Sasi, we have a proposed patch. Bug is assigned to your name. Perhaps you just
> want to rebase & glance over the fix before pushing?
Sure, on it right away
Comment 17 Sasikanth Bharadwaj CLA 2017-04-12 08:48:46 EDT
(In reply to comment #16)
> Gerrit change https://git.eclipse.org/r/73460 was merged to [master].
> Commit:
> http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=30b8634488c2a308787d6f4bc05e881c37e80405
Done, resolving. Thanks Stephan for the patch
Comment 18 Manoj N Palat CLA 2017-05-09 08:14:27 EDT
Verified for Eclipse Oxygen 4.7M7 Build id: I20170508-2000