After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 567269 - Report an error when using "this" before chaining up to the base class
Report an error when using "this" before chaining up to the base class
Status: RESOLVED OBSOLETE
Product: vala
Classification: Core
Component: Control Flow Statements
unspecified
Other All
: Urgent blocker
: 1.0
Assigned To: Vala maintainers
Vala maintainers
wrong-code test-case
: 591752 598487 604299 611490 632734 646286 793549 (view as bug list)
Depends on:
Blocks: 632734
 
 
Reported: 2009-01-10 16:05 UTC by ccadete
Modified: 2018-05-22 13:16 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Fix is_chainup method (1.24 KB, patch)
2013-04-02 12:01 UTC, Simon Werbeck
none Details | Review
Report error when using this before before chain-up (4.44 KB, patch)
2013-04-02 12:02 UTC, Simon Werbeck
needs-work Details | Review
Report error when using this before before chain-up (4.44 KB, patch)
2013-04-02 14:42 UTC, Simon Werbeck
rejected Details | Review
Report error when using this before before chain-up (3.67 KB, patch)
2013-04-03 13:00 UTC, Simon Werbeck
none Details | Review
Report error when using this before before chain-up (4.62 KB, patch)
2013-04-06 09:26 UTC, Simon Werbeck
none Details | Review
Report error when using this before before chain-up (4.62 KB, patch)
2013-04-06 10:15 UTC, Simon Werbeck
none Details | Review
Report error when using this before before chain-up (4.95 KB, patch)
2013-04-06 11:24 UTC, Simon Werbeck
none Details | Review
Report error when using this before before chain-up (10.35 KB, patch)
2013-05-30 15:38 UTC, Simon Werbeck
needs-work Details | Review
Report error when using this before before chain-up (11.67 KB, patch)
2013-06-09 09:56 UTC, Simon Werbeck
needs-work Details | Review
Improve constructor chain-up checks (5.59 KB, patch)
2014-11-26 13:21 UTC, Simon Werbeck
committed Details | Review
Warn when using this before chain up (5.34 KB, patch)
2014-11-26 13:21 UTC, Simon Werbeck
none Details | Review
Make lambdas work in chain ups again (2.65 KB, patch)
2014-11-26 13:22 UTC, Simon Werbeck
none Details | Review
Allow 'static' lambdas before chain up (3.24 KB, patch)
2014-11-26 13:23 UTC, Simon Werbeck
none Details | Review
Test cases for valid/invalid chainups (1.38 KB, application/x-xz)
2014-11-26 13:45 UTC, Simon Werbeck
  Details
Allow multiple chain-up calls in the constructor (3.09 KB, patch)
2014-11-27 14:43 UTC, Simon Werbeck
none Details | Review
Also track instance access when using generic types (4.66 KB, patch)
2014-11-28 16:02 UTC, Simon Werbeck
none Details | Review
tests: Add some invalid "chain-up" tests (6.27 KB, patch)
2018-02-19 16:19 UTC, Rico Tzschichholz
none Details | Review

Description ccadete 2009-01-10 16:05:44 UTC
Please describe the problem:
Should not be possible to use "this" before executing the base class constructors

Steps to reproduce:


using GLib;


public class ClassA : Object {

  public ClassA(ClassB param){
    stdout.printf ("ClassA\n");
  }

}

public class ClassB : ClassA {

  public ClassB(){
    base(this);
    stdout.printf ("ClassB\n");
  }

/*
  NOTE: Using "this" in method, should not be possible too

  public ClassB(){
    base(util(this));
    stdout.printf ("ClassB\n");
  }

  public static ClassB util (ClassB p){
    return p;
  }
*/

  public static void main (string[] args) {
    new ClassB();
  }

}



Actual results:
critical warning

Expected results:


Does this happen every time?


Other information:
Comment 1 James "Doc" Livingston 2009-06-26 00:32:51 UTC
The same problem occurs when calling instance methods of the class before base(), it compiles without warning and fails at run time.

classC: Object {
  public classC() {
    someMethod();
    base();
  }

  someMethod() {
     ...
  }
}
Comment 2 Jürg Billeter 2009-08-16 21:04:07 UTC
*** Bug 591752 has been marked as a duplicate of this bug. ***
Comment 3 Jürg Billeter 2010-03-22 21:09:59 UTC
*** Bug 611490 has been marked as a duplicate of this bug. ***
Comment 4 Jürg Billeter 2010-03-22 21:37:36 UTC
*** Bug 598487 has been marked as a duplicate of this bug. ***
Comment 5 Jürg Billeter 2010-10-14 15:15:30 UTC
*** Bug 604299 has been marked as a duplicate of this bug. ***
Comment 6 Jürg Billeter 2011-04-02 14:02:00 UTC
*** Bug 646286 has been marked as a duplicate of this bug. ***
Comment 7 Luca Bruno 2013-03-25 12:10:29 UTC
This shouldn't be hard to implement in the control flow check by checking for the "this" parameter being used before being initialized, right? Much like what we did for out parameters.
Comment 8 Simon Werbeck 2013-04-02 12:01:31 UTC
Created attachment 240371 [details] [review]
Fix is_chainup method

The is_chainup method didn't accept all forms of chain-up calls. Now this(), base() and Object() are supported as well

Required for bug 567269
Comment 9 Simon Werbeck 2013-04-02 12:02:34 UTC
Created attachment 240372 [details] [review]
Report error when using this before before chain-up

Fixes bug 567269
Comment 10 Luca Bruno 2013-04-02 13:52:45 UTC
Review of attachment 240372 [details] [review]:

This looks quite safe thanks.

::: vala/valaflowanalyzer.vala
@@ +418,3 @@
 							// parameter
+							if (used_var.name == "this") {
+								Report.error (used_var.source_reference, "use of possibly unassigned local variable `%s'".printf (used_var.name));

Here we need an error specifically for "this". Something like: can't reference "this" before chaining up, or something like that.

::: vala/valamemberaccess.vala
@@ +924,3 @@
 		if (local != null) {
 			collection.add (local);
+		} else if (param != null && (param.direction == ParameterDirection.OUT || param.name == "this" && param.parent_node is CreationMethod && ((CreationMethod)param.parent_node).chain_up)) {

What if you use parent_symbol instead of parent_node?

::: vala/valamethodcall.vala
@@ +801,3 @@
+			var this_parameter = call.symbol_reference as Parameter;
+			if (this_parameter == null) {
+				var stmt = parent_statement;

You should be able to do (Block) parent_statement.parent_node; here. That I know, Block is the only container of statements.
Comment 11 Simon Werbeck 2013-04-02 14:42:21 UTC
Created attachment 240393 [details] [review]
Report error when using this before before chain-up

Addressed the mentioned issues:
- Change error message to something more meaningful
- use parent_symbol, no need to set parent_node for this_parameter
- cast directly to Block
Comment 12 Luca Bruno 2013-04-03 07:21:21 UTC
Review of attachment 240393 [details] [review]:

It seems you attached the same patch as before.
Comment 13 Luca Bruno 2013-04-03 07:27:05 UTC
Also, the patch seems to introduce a regression for structs:

public struct Foo {
        int i;
        public Foo () {
                this.bar();
                i=2;
        }
        public Foo.bar () {
        }
}

void main () {
}

With the patch it errors out, but it shouldn't.
Comment 14 Simon Werbeck 2013-04-03 13:00:00 UTC
Created attachment 240475 [details] [review]
Report error when using this before before chain-up

My bad, here is the correct version. With this patch I could not reproduce the error you found. However, I found another bug related to fixing this one:

struct Foo {
    public Foo () {}
    public Foo.foo () {}
    public Foo.bar () {
        this ();
        this ();
        this.foo ();
    }
}

Compiles without errors on master. The fix for bug 608548 might be related. There 'is_chainup' was added in order to only consider CreationMethods as chain-ups.
Comment 15 Simon Werbeck 2013-04-03 13:03:55 UTC
Also currently my patch breaks Object chain-ups because is_chainup returns false for Object() calls.
Comment 16 Simon Werbeck 2013-04-06 09:26:05 UTC
Created attachment 240826 [details] [review]
Report error when using this before before chain-up

I was wrong in that the previous patch did indeed introduce a regression. Since chain-ups to named constructors of struct are replaced by ObjectCreationExpressions, those were not found in the MethodCall.get_defined_variables.
What's now left are:
- this() chain-up in structs: the semantic analyzer needs to find those as well.
- Object() chain-up: not sure how I could find that from is_chainup. I'm not in the semantic analyzer pass anymore so I can't just compare with analyzer.object_type.
Comment 17 Luca Bruno 2013-04-06 10:03:59 UTC
this() chain up in structs work, what's the problem? this.foo() doesn't work, so don't bother about that now.

Object(): CodeContext.get().analyzer
Comment 18 Simon Werbeck 2013-04-06 10:11:35 UTC
Ah sorry, I meant the flow check for this() chain-up in structs. this() for structs is not recorded with chain_up = true and so no error is reported for the following:

public struct Foo {
	int i;
	public Foo () {}
	public Foo.foo () {
		i = 1;
		this ();
	}
}

void main () {
}
Comment 19 Simon Werbeck 2013-04-06 10:15:59 UTC
Created attachment 240827 [details] [review]
Report error when using this before before chain-up

Make is_chainup recognize Object()
Comment 20 Luca Bruno 2013-04-06 11:18:45 UTC
Your new patch doesn't change is_chainup.
Comment 21 Simon Werbeck 2013-04-06 11:24:06 UTC
Created attachment 240832 [details] [review]
Report error when using this before before chain-up

Right, something went wrong with git format-patch. This should be the correct patch.
Comment 22 Simon Werbeck 2013-05-30 15:38:26 UTC
Created attachment 245655 [details] [review]
Report error when using this before before chain-up

Changes in this patch:

* Changed the way check() looks for chain-ups. Should also fix bug 697342.
* is_chainup is now a property set by check(); also added a property 'struct_chainup' to ObjectCreationExpression as struct invocations are transformed.
* Made sure lambda expressions in CreationMethods define 'this'
Comment 23 Luca Bruno 2013-05-30 18:27:08 UTC
Review of attachment 245655 [details] [review]:

Thanks for the patch. However, lambda expression do not define "this", but use "this".

The following must be an error:

class Foo : Object {
        int i;
        Foo () {
                SourceFunc foo = () => { return i++ == 0;};
                base();
        }
}

The following is fine:

class Foo : Object {
        int i;
        Foo () {
                base();
                SourceFunc foo = () => { return i++ == 0;};
        }
}

Other than that, the patch looks fine overall.

Lambdas at a whole must be threaten like any other "this" usage.
Comment 24 Luca Bruno 2013-05-30 18:28:26 UTC
Notice that lambdas may or may not capture "this". They use "this" only if "this" is captured, i.e. when the lambda is a closure.
Comment 25 Simon Werbeck 2013-06-09 09:56:06 UTC
Created attachment 246348 [details] [review]
Report error when using this before before chain-up

* don't define 'this' parameter, add to used variables of lambdaexpression.
* Create new 'this' parameter for the generated method so we don't reference the creation method

Fixes bug 567269
Comment 26 Luca Bruno 2013-06-15 09:41:25 UTC
Review of attachment 246348 [details] [review]:

Thanks for the patch. Anyway, did you ever try using lambdas in creation methods? This must work:

public class Bar {
        public Bar () {
                SourceFunc f = () => { return true; };
        }
}

void main () {
}

::: vala/valaflowanalyzer.vala
@@ +418,3 @@
 							// parameter
+							if (used_var.name == "this") {
+								Report.error (used_var.source_reference, "can't reference `this' before chaining up");

Please issue a warning here, "possible reference to `this' before chaining up".

@@ +454,3 @@
 						// parameter
+						if (var_symbol.name == "this") {
+							Report.error (node.source_reference, "can't reference `this' before chaining up");

Warning here.

::: vala/valalambdaexpression.vala
@@ +255,3 @@
+		if (captures_creation_method) {
+			Symbol sym = (Block)parent_statement.parent_node;
+			do {

Is this necessary for this patch to work? And why?
Comment 27 Simon Werbeck 2014-11-26 13:21:07 UTC
Created attachment 291542 [details] [review]
Improve constructor chain-up checks

I decided to work on this once more and I think it is complete now. I split the changes into smaller patches to make them easier to understand.
Comment 28 Simon Werbeck 2014-11-26 13:21:45 UTC
Created attachment 291543 [details] [review]
Warn when using this before chain up
Comment 29 Simon Werbeck 2014-11-26 13:22:18 UTC
Created attachment 291544 [details] [review]
Make lambdas work in chain ups again
Comment 30 Simon Werbeck 2014-11-26 13:23:13 UTC
Created attachment 291545 [details] [review]
Allow 'static' lambdas before chain up
Comment 31 Simon Werbeck 2014-11-26 13:45:13 UTC
Created attachment 291546 [details]
Test cases for valid/invalid chainups

Thought I'd also share the test cases I used. With all patches applied, all tests should pass. Also contains negative tests (those must fail) so I can't add them to the official tests.
Comment 32 Luca Bruno 2014-11-26 13:57:23 UTC
Missing negative test cases in our compiler is very bad. Hope I can work on it soon. It's not trivial due to performance bottlenecks when using make check.

Thanks for the patches will look at them.
Comment 33 Luca Bruno 2014-11-26 20:53:03 UTC
The following code says there are multiple constructor calls:

class Foo : Object {
	public Foo () {
		var a = 2+3 == 5;
		if (a) {
			Object();
		} else {
			Object();
		}
	}
}

void main () {
}

It's the last standing in valamethodcall.vala

---

The following code must warn, because if the method is marked to chain up, it must chain up always:

class Foo : Object {
	public Foo () {
		var a = 2+3 == 5;
		if (a) {
			Object();
		}
	}
}

void main () {
}

This is fixable in the flowanalyzer, similar to out parameters by checking at the end of the method that "this" is being defined.
Comment 34 Luca Bruno 2014-11-26 21:05:41 UTC
To point it out, you are doing a really *great* work. Sorry for rejecting the patches as needs-work, however I'd like to fix this once for all and not think about it once again.
Comment 35 Simon Werbeck 2014-11-27 14:43:14 UTC
Created attachment 291655 [details] [review]
Allow multiple chain-up calls in the constructor

Ok, how about this? I had the concern that this would allow reassignment to 'this', for example:

class Foo : Object {
    public Foo ()
        Object ();
        if (2 == 2) {
            Object();  // maybe already init'd
        }
    }
}


So I added a warning in cases like this. Another possibility is to unref 'this' before chainup (if not NULL).
Comment 36 Luca Bruno 2014-11-27 14:47:27 UTC
A warning is fine. We cannot first create then unref, as constructors may have side effects.
Comment 37 Simon Werbeck 2014-11-27 15:30:12 UTC
Just saw that my 4th patch introduces a bug in combination with generics, will have to look at it later.
Comment 38 Simon Werbeck 2014-11-28 16:02:10 UTC
Created attachment 291729 [details] [review]
Also track instance access when using generic types

This should fix the last bug. Variables with generic types implicitly need instance access in order to call the destroy/dup functions of the type parameter.
Comment 39 Luca Bruno 2014-11-28 16:04:43 UTC
Right. Good catch, will review.
Comment 40 Luca Bruno 2015-03-13 09:52:09 UTC
Review of attachment 291729 [details] [review]:

I'm not able to udnerstand the need of this patch, can you provide a quick test case of when is this needed?
Comment 41 Simon Werbeck 2015-03-14 12:45:20 UTC
Ok, this is what I came up with. I guess it is a rather uncommon case but still:

public class Test<G> : Object {
	public Test () {
		SourceFunc f = () => {
			G a = null;
			G b = a;
			return true;
		};
		f ();

		Object ();
	}

	static void main () {
	}
}

In the generated function you can see that generic dup/free functions are accessed which require self to be initialized.
Comment 42 Simon Werbeck 2015-03-14 12:54:09 UTC
Actually the example compiles just fine as 'a' is null. A better example would involve capturing a generic variable/parameter, which is prevented by bug 746200.
Comment 43 Rico Tzschichholz 2016-12-08 10:23:32 UTC
Comment on attachment 291542 [details] [review]
Improve constructor chain-up checks

commit 73b9e4b4a2c059ceb6bce7ab173050fb70739892
Author: Simon Werbeck <simon.werbeck@gmail.com>
Date:   Wed Nov 26 11:53:31 2014 +0100

    Improve constructor chain-up checks
Comment 44 Daniel Espinosa 2017-02-20 17:23:00 UTC
If this should be fixed by calling first base constructors, as should be, this should not be a bug but a programming error, following GObject construction rules. At the end Vala code is GObject, then you should know very well how it is working in order to avoid object construction errors.

Set is as non-bug. Feel free to create a new one as enhancement on GObject construction checks, but tagged for Vala 2.0.
Comment 45 Rico Tzschichholz 2017-02-20 18:15:56 UTC
Please this open.
Comment 46 Rico Tzschichholz 2017-02-20 18:16:11 UTC
Please leave this open.
Comment 47 Al Thomas 2017-02-20 19:02:04 UTC
(In reply to Daniel Espinosa from comment #44)
> If this should be fixed by calling first base constructors, as should be,
> this should not be a bug but a programming error, following GObject
> construction rules. At the end Vala code is GObject, then you should know
> very well how it is working in order to avoid object construction errors.
> 
> Set is as non-bug. Feel free to create a new one as enhancement on GObject
> construction checks, but tagged for Vala 2.0.

This bug has significant work done on it. Maybe it is not a "bug" because you argue it is programmer error, but it is certainly an "enhancement" and with several patches being submitted. To close this report and ask for a new submission is counter-productive.

I have looked over this recently and the comments suggest it is close to completion. It may also serve as a useful example of using the flow analyzer in Vala.

Comment 31 has a zip file of test cases, both pass and fail. What would be really helpful would be to change those zipped tests into a patch that can be applied to /tests in Vala.
Comment 48 Rico Tzschichholz 2017-02-20 19:15:31 UTC
The patches are staged here for some time.
https://git.gnome.org/browse/vala/log/?h=wip/bug567269
Comment 49 Daiki Ueno 2017-03-28 13:21:31 UTC
I am surprised that the following code no longer compiles after commit 73b9e4b4a2c059ceb6bce7ab173050fb70739892.  Is it intended?

$ cat > chainup.vala <<EOF
class Foo : Object {
    public Foo.with_foo (int a) {
        print (a.to_string ());
    }
    public Foo.with_bar (int b) {
        with_foo (b); // "this." is omitted
    }
}
EOF

$ valac -C chainup.vala
chainup.vala:6.9-6.20: error: use `new' operator to create new objects
        with_foo (b);
        ^^^^^^^^^^^^
Compilation failed: 1 error(s), 0 warning(s)

The compiler suggest to use `new' here, but that makes the generated code return unref()'ed object.
Comment 50 Rico Tzschichholz 2018-02-17 21:39:44 UTC
*** Bug 793549 has been marked as a duplicate of this bug. ***
Comment 51 Rico Tzschichholz 2018-02-19 16:19:24 UTC
Created attachment 368568 [details] [review]
tests: Add some invalid "chain-up" tests
Comment 52 Rico Tzschichholz 2018-02-19 16:20:50 UTC
*** Bug 632734 has been marked as a duplicate of this bug. ***
Comment 53 GNOME Infrastructure Team 2018-05-22 13:16:27 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/vala/issues/22.